HPET driver for testing HPET code more easily.

Seems to work correctly on real hardware, not on qemu where it
can only use the irq 2, and this causes wreakage (could be a programming error).
Changed from the kernel code:
- Adapted to use as a driver
- Configure for level interrupts instead of edge, which seems not to work correctly
- Add traceing dprintfs
- Various other changes
Does not use yet the new interrupt api introduced by Michael Lotz.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42837 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini
2011-10-13 08:20:10 +00:00
parent 2e77a03d92
commit 79e3f9012d
8 changed files with 898 additions and 0 deletions
+1
View File
@@ -16,4 +16,5 @@ SubInclude HAIKU_TOP src add-ons kernel drivers power ;
SubInclude HAIKU_TOP src add-ons kernel drivers printer ;
SubInclude HAIKU_TOP src add-ons kernel drivers random ;
SubInclude HAIKU_TOP src add-ons kernel drivers tty ;
SubInclude HAIKU_TOP src add-ons kernel drivers timer ;
SubInclude HAIKU_TOP src add-ons kernel drivers video ;
+6
View File
@@ -0,0 +1,6 @@
SubDir HAIKU_TOP src add-ons kernel drivers timer ;
UsePrivateHeaders drivers ;
KernelAddon <driver>hpet :
hpet.cpp ;
@@ -0,0 +1,206 @@
/*
* Copyright 2008, Dustin Howett, [email protected]. All rights reserved.
* Copyright 2007, Michael Lotz, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_ARCH_x86_ARCH_ACPI_H
#define _KERNEL_ARCH_x86_ARCH_ACPI_H
#define ACPI_RSDP_SIGNATURE "RSD PTR "
#define ACPI_RSDT_SIGNATURE "RSDT"
#define ACPI_XSDT_SIGNATURE "XSDT"
#define ACPI_MADT_SIGNATURE "APIC"
#define ACPI_LOCAL_APIC_ENABLED 0x01
typedef struct acpi_rsdp_legacy {
char signature[8]; /* "RSD PTR " including blank */
uint8 checksum; /* checksum of bytes 0-19 (per ACPI 1.0) */
char oem_id[6]; /* not null terminated */
uint8 revision; /* 0 = ACPI 1.0, 2 = ACPI 3.0 */
uint32 rsdt_address; /* physical memory address of RSDT */
} _PACKED acpi_rsdp_legacy;
typedef struct acpi_rsdp_extended {
char signature[8]; /* "RSD PTR " including blank */
uint8 checksum; /* checksum of bytes 0-19 (per ACPI 1.0) */
char oem_id[6]; /* not null terminated */
uint8 revision; /* 0 = ACPI 1.0, 2 = ACPI 3.0 */
uint32 rsdt_address; /* physical memory address of RSDT */
uint32 xsdt_length; /* length in bytes including header */
uint64 xsdt_address; /* 64bit physical memory address of XSDT */
uint8 extended_checksum; /* including entire table */
uint8 reserved[3];
} _PACKED acpi_rsdp_extended;
typedef acpi_rsdp_extended acpi_rsdp;
typedef struct acpi_descriptor_header {
char signature[4]; /* table identifier as ASCII string */
uint32 length; /* length in bytes of the entire table */
uint8 revision;
uint8 checksum; /* checksum of entire table */
char oem_id[6]; /* not null terminated */
char oem_table_id[8]; /* oem supplied table identifier */
uint32 oem_revision; /* oem supplied revision number */
char creator_id[4]; /* creator / asl compiler id */
uint32 creator_revision; /* compiler revision */
} _PACKED acpi_descriptor_header;
typedef struct acpi_madt {
acpi_descriptor_header header; /* "APIC" signature */
uint32 local_apic_address; /* physical address for local CPUs APICs */
uint32 flags;
} _PACKED acpi_madt;
enum {
ACPI_MADT_LOCAL_APIC = 0,
ACPI_MADT_IO_APIC = 1,
ACPI_MADT_INTERRUPT_SOURCE_OVERRIDE = 2,
ACPI_MADT_NMI_SOURCE = 3,
ACPI_MADT_LOCAL_APIC_NMI = 4,
ACPI_MADT_LOCAL_APIC_ADDRESS_OVERRIDE = 5,
ACPI_MADT_IO_SAPIC = 6,
ACPI_MADT_LOCAL_SAPIC = 7,
ACPI_MADT_PLATFORM_INTERRUPT_SOURCE = 8,
ACPI_MADT_PROCESSOR_LOCAL_X2_APIC_NMI = 9,
ACPI_MADT_LOCAL_X2_APIC_NMI = 0XA
};
typedef struct acpi_apic {
uint8 type;
uint8 length;
} _PACKED acpi_apic;
typedef struct acpi_local_apic {
uint8 type; /* 0 = processor local APIC */
uint8 length; /* 8 bytes */
uint8 acpi_processor_id;
uint8 apic_id; /* the id of this APIC */
uint32 flags; /* 1 = enabled */
} _PACKED acpi_local_apic;
typedef struct acpi_io_apic {
uint8 type; /* 1 = I/O APIC */
uint8 length; /* 12 bytes */
uint8 io_apic_id; /* the id of this APIC */
uint8 reserved;
uint32 io_apic_address; /* physical address of I/O APIC */
uint32 interrupt_base; /* global system interrupt base */
} _PACKED acpi_io_apic;
typedef struct acpi_int_source_override {
uint8 type; /* 2 = Interrupt source override */
uint8 length; /* 10 bytes */
uint8 bus; /* 0 = ISA */
uint8 source; /* Bus-relative interrupt source (IRQ) */
uint32 interrupt; /* global system interrupt this
bus-relative source int will signal */
uint16 flags; /* MPS INTI flags. See Table 5-25 in
ACPI Spec 4.0a or similar */
} _PACKED acpi_int_source_override;
typedef struct acpi_nmi_source {
uint8 type; /* 3 = NMI */
uint8 length; /* 8 bytes */
uint16 flags; /* Same as MPS INTI flags. See Table 5-25 in
ACPI Spec 4.0a or similar */
uint32 interrupt; /* global system interrupt this
non-maskable interrupt will trigger */
} _PACKED acpi_nmi_source;
typedef struct acpi_local_apic_nmi {
uint8 type; /* 4 = local APIC NMI */
uint8 length; /* 6 bytes */
uint8 acpi_processor_id; /* Processor ID corresponding to processor
ID in acpi_local_apic. 0xFF means
it applies to all processors */
uint16 flags; /* Same as MPS INTI flags. See Table 5-25 in
ACPI Spec 4.0a or similar */
uint8 local_interrupt; /* Local APIC interrupt input LINTn to which
NMI is connected */
} _PACKED acpi_local_apic_nmi;
typedef struct acpi_local_apic_address_override {
uint8 type; /* 5 = local APIC address override */
uint8 length; /* 12 bytes */
uint16 reserved; /* reserved (must be set to zero) */
uint64 local_apic_address; /* Physical address of local APIC. See table
5-28 in ACPI Spec 4.0a for more */
} _PACKED acpi_local_apic_address_override;
typedef struct acpi_io_sapic {
uint8 type; /* 6 = I/0 SAPIC (should be used if it
exists instead of I/O APIC if both exists
for a APIC ID.*/
uint8 length; /* 16 bytes */
uint8 io_apic_id; /* the id of this SAPIC */
uint8 reserved; /* reserved (must be set to zero) */
uint32 interrupt_base; /* global system interrupt base */
uint64 sapic_address; /* The physical address to access this I/0
SAPIC. Each SAPIC resides at a unique
address */
} _PACKED acpi_io_sapic;
typedef struct acpi_local_sapic {
uint8 type; /* 7 = processor local SAPIC */
uint8 length; /* n bytes */
uint8 acpi_processor_id;
uint8 local_sapic_id;
uint8 local_sapic_eid;
uint8 reserved1; /* reserved (must be set to zero) */
uint8 reserved2; /* reserved (must be set to zero) */
uint8 reserved3; /* reserved (must be set to zero) */
uint32 flags; /* Local SAPIC flags, see table 5-22 in
ACPI Spec 4.0a */
uint32 processor_uid_nr; /* Matches _UID of a processor when it is a
number */
char processor_uid_str[]; /* Matches _UID of a processor when it is a
string. Null-terminated */
} _PACKED acpi_local_sapic;
typedef struct acpi_platform_interrupt_source {
uint8 type; /* 8 = platform interrupt source */
uint8 length; /* 16 bytes */
uint16 flags; /* Same as MPS INTI flags. See Table 5-25 in
ACPI Spec 4.0a or similar */
uint8 interrupt_type; /* 1 PMI, 2 INIT, 3 Corrected Platform
Error Interrupt */
uint8 processor_id; /* processor ID of destination */
uint8 processor_eid; /* processor EID of destination */
uint8 io_sapic_vector; /* value that must be used to program the
vector field of the I/O SAPIC redirection
entry for entries with PMI type. */
uint32 interrupt; /* global system interrupt this
platform interrupt will trigger */
uint32 platform_int_flags; /* Platform Interrupt Source Flags. See
Table 5-32 of ACPI Spec 4.0a for desc */
} _PACKED acpi_platform_interrupt_source;
typedef struct acpi_local_x2_apic {
uint8 type; /* 9 = processor local x2APIC */
uint8 length; /* 16 bytes */
uint16 reserved; /* reserved (must be zero) */
uint32 x2apic_id; /* processor's local x2APIC ID */
uint32 flags; /* 1 = enabled. */
uint32 processor_uid_nr; /* Matches _UID of a processor when it is a
number */
} _PACKED acpi_local_x2_apic;
typedef struct acpi_local_x2_apic_nmi {
uint8 type; /* 0xA = local x2APIC NMI */
uint8 length; /* 12 bytes */
uint16 flags; /* Same as MPS INTI flags. See Table 5-25 in
ACPI Spec 4.0a or similar */
uint32 acpi_processor_uid; /* UID corresponding to ID in processor
device object. 0xFFFFFFFF means
it applies to all processors */
uint8 local_interrupt; /* Local x2APIC interrupt input LINTn to
which NMI is connected */
uint8 reserved1; /* reserved (must be set to zero) */
uint8 reserved2; /* reserved (must be set to zero) */
uint8 reserved3; /* reserved (must be set to zero) */
} _PACKED acpi_local_x2_apic_nmi;
#endif /* _KERNEL_ARCH_x86_ARCH_ACPI_H */
+508
View File
@@ -0,0 +1,508 @@
/*
* Copyright 2009-2010, Stefano Ceccherini ([email protected])
* Copyright 2008, Dustin Howett, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#include "hpet.h"
#include "hpet_interface.h"
#include "int.h"
#include "msi.h"
#include <Drivers.h>
#include <KernelExport.h>
#include <ACPI.h>
#include <PCI.h>
#include <stdlib.h>
#include <string.h>
#define TRACE_HPET
#ifdef TRACE_HPET
#define TRACE(x) dprintf x
#else
#define TRACE(x) ;
#endif
#define TEST_HPET
static struct hpet_regs *sHPETRegs;
static uint64 sHPETPeriod;
static area_id sHPETArea;
struct hpet_timer_cookie {
int number;
int32 irq;
sem_id sem;
};
////////////////////////////////////////////////////////////////////////////////
static status_t hpet_open(const char*, uint32, void**);
static status_t hpet_close(void*);
static status_t hpet_free(void*);
static status_t hpet_control(void*, uint32, void*, size_t);
static ssize_t hpet_read(void*, off_t, void*, size_t*);
static ssize_t hpet_write(void*, off_t, const void*, size_t*);
////////////////////////////////////////////////////////////////////////////////
static const char* hpet_name[] = {
"misc/hpet",
NULL
};
device_hooks hpet_hooks = {
hpet_open,
hpet_close,
hpet_free,
hpet_control,
hpet_read,
hpet_write,
};
int32 api_version = B_CUR_DRIVER_API_VERSION;
static acpi_module_info* sAcpi;
static vint32 sOpenCount;
static inline bigtime_t
hpet_convert_timeout(const bigtime_t &relativeTimeout)
{
bigtime_t counter = sHPETRegs->u0.counter64;
bigtime_t converted = (1000000000ULL / sHPETPeriod) * relativeTimeout;
dprintf("counter: %lld, relativeTimeout: %lld, converted: %lld\n",
counter, relativeTimeout, converted);
return converted + counter;
}
#define MIN_TIMEOUT 3000
static status_t
hpet_set_hardware_timer(bigtime_t relativeTimeout, volatile hpet_timer *timer)
{
// TODO:
if (relativeTimeout < MIN_TIMEOUT)
relativeTimeout = MIN_TIMEOUT;
bigtime_t timerValue = hpet_convert_timeout(relativeTimeout);
//dprintf("comparator: %lld, new value: %lld\n", timer->u0.comparator64, timerValue);
timer->u0.comparator64 = timerValue;
// enable timer interrupt
timer->config |= HPET_CONF_TIMER_INT_ENABLE;
return B_OK;
}
static status_t
hpet_clear_hardware_timer(volatile hpet_timer *timer)
{
// Disable timer interrupt
timer->config &= ~HPET_CONF_TIMER_INT_ENABLE;
return B_OK;
}
static int32
hpet_timer_interrupt(void *arg)
{
//dprintf("HPET timer_interrupt!!!!\n");
hpet_timer_cookie* hpetCookie = (hpet_timer_cookie*)arg;
// clear interrupt status
int32 intStatus = 1 << hpetCookie->number;
if (sHPETRegs->interrupt_status & intStatus) {
sHPETRegs->interrupt_status |= intStatus;
hpet_clear_hardware_timer(&sHPETRegs->timer[hpetCookie->number]);
release_sem(hpetCookie->sem);
return B_HANDLED_INTERRUPT;
}
return B_UNHANDLED_INTERRUPT;
}
static status_t
hpet_set_enabled(bool enabled)
{
if (enabled)
sHPETRegs->config |= HPET_CONF_MASK_ENABLED;
else
sHPETRegs->config &= ~HPET_CONF_MASK_ENABLED;
return B_OK;
}
static status_t
hpet_set_legacy(bool enabled)
{
if (!HPET_IS_LEGACY_CAPABLE(sHPETRegs)) {
dprintf("hpet_init: HPET doesn't support legacy mode. Skipping.\n");
return B_NOT_SUPPORTED;
}
if (enabled)
sHPETRegs->config |= HPET_CONF_MASK_LEGACY;
else
sHPETRegs->config &= ~HPET_CONF_MASK_LEGACY;
return B_OK;
}
#ifdef TRACE_HPET
static void
hpet_dump_timer(volatile struct hpet_timer *timer)
{
dprintf("HPET Timer %ld:\n", (timer - sHPETRegs->timer));
dprintf("CAP/CONFIG register: 0x%llx\n", timer->config);
dprintf("Capabilities:\n");
dprintf("\troutable IRQs: ");
uint32 interrupts = (uint32)HPET_GET_CAP_TIMER_ROUTE(timer);
for (int i = 0; i < 32; i++) {
if (interrupts & (1 << i))
dprintf("%d ", i);
}
dprintf("\n\tsupports FSB delivery: %s\n",
timer->config & HPET_CAP_TIMER_FSB_INT_DEL ? "Yes" : "No");
dprintf("\n");
dprintf("Configuration:\n");
dprintf("\tFSB Enabled: %s\n",
timer->config & HPET_CONF_TIMER_FSB_ENABLE ? "Yes" : "No");
dprintf("\tInterrupt Enabled: %s\n",
timer->config & HPET_CONF_TIMER_INT_ENABLE ? "Yes" : "No");
dprintf("\tTimer type: %s\n",
timer->config & HPET_CONF_TIMER_TYPE ? "Periodic" : "OneShot");
dprintf("\tInterrupt Type: %s\n",
timer->config & HPET_CONF_TIMER_INT_TYPE ? "Level" : "Edge");
dprintf("\tconfigured IRQ: %lld\n",
HPET_GET_CONF_TIMER_INT_ROUTE(timer));
if (timer->config & HPET_CONF_TIMER_FSB_ENABLE) {
dprintf("\tfsb_route[0]: 0x%llx\n", timer->fsb_route[0]);
dprintf("\tfsb_route[1]: 0x%llx\n", timer->fsb_route[1]);
}
}
#endif
static void
hpet_init_timer(volatile struct hpet_timer *timer)
{
uint32 interrupts = (uint32)HPET_GET_CAP_TIMER_ROUTE(timer);
// TODO: Check if the interrupt is already used, and try another
uint32 interrupt = 0;
for (int i = 0; i < 32; i++) {
if (interrupts & (1 << i)) {
interrupt = i;
break;
}
}
timer->config = 0;
timer->config |= (interrupt << HPET_CONF_TIMER_INT_ROUTE_SHIFT)
& HPET_CONF_TIMER_INT_ROUTE_MASK;
// Non-periodic mode
timer->config &= ~HPET_CONF_TIMER_TYPE;
// level triggered
timer->config |= HPET_CONF_TIMER_INT_TYPE;
// Disable FSB/MSI, enable 64 bit mode
timer->config &= ~HPET_CONF_TIMER_FSB_ENABLE;
timer->config &= ~HPET_CONF_TIMER_32MODE;
#ifdef TRACE_HPET
hpet_dump_timer(timer);
#endif
}
static status_t
hpet_configure_interrupt(volatile hpet_timer* timer, int32 *irq)
{
status_t status = B_OK;
*irq = HPET_GET_CONF_TIMER_INT_ROUTE(timer);
// TODO: Configure interrupt using msi or regular irqs
return status;
}
static status_t
hpet_test()
{
uint64 initialValue = sHPETRegs->u0.counter64;
spin(10);
uint64 finalValue = sHPETRegs->u0.counter64;
if (initialValue == finalValue) {
dprintf("hpet_test: counter does not increment\n");
return B_ERROR;
}
return B_OK;
}
static status_t
hpet_init()
{
if (sHPETRegs == NULL)
return B_NO_INIT;
sHPETPeriod = HPET_GET_PERIOD(sHPETRegs);
TRACE(("hpet_init: HPET is at %p.\n\tVendor ID: %llx, rev: %llx, period: %lld\n",
sHPETRegs, HPET_GET_VENDOR_ID(sHPETRegs), HPET_GET_REVID(sHPETRegs),
sHPETPeriod));
status_t status = hpet_set_enabled(false);
if (status != B_OK)
return status;
status = hpet_set_legacy(false);
if (status != B_OK)
return status;
uint32 numTimers = HPET_GET_NUM_TIMERS(sHPETRegs) + 1;
TRACE(("hpet_init: HPET supports %lu timers, and is %s bits wide.\n",
numTimers, HPET_IS_64BIT(sHPETRegs) ? "64" : "32"));
TRACE(("hpet_init: configuration: 0x%llx, timer_interrupts: 0x%llx\n",
sHPETRegs->config, sHPETRegs->interrupt_status));
if (numTimers < 3) {
dprintf("hpet_init: HPET does not have at least 3 timers. Skipping.\n");
return B_ERROR;
}
/*
#ifdef TRACE_HPET
for (uint32 c = 0; c < numTimers; c++)
hpet_dump_timer(&sHPETRegs->timer[c]);
#endif
*/
sHPETRegs->interrupt_status = 0;
status = hpet_set_enabled(true);
if (status != B_OK)
return status;
#ifdef TEST_HPET
status = hpet_test();
if (status != B_OK)
return status;
#endif
return status;
}
////////////////////////////////////////////////////////////////////////////////
status_t
init_hardware(void)
{
return B_OK;
}
status_t
init_driver(void)
{
sOpenCount = 0;
status_t status = get_module(B_ACPI_MODULE_NAME, (module_info**)&sAcpi);
if (status < B_OK)
return status;
acpi_hpet *hpetTable;
status = sAcpi->get_table(ACPI_HPET_SIGNATURE, 0,
(void**)&hpetTable);
if (status != B_OK) {
put_module(B_ACPI_MODULE_NAME);
return status;
}
sHPETArea = map_physical_memory("HPET registries",
hpetTable->hpet_address.address, B_PAGE_SIZE, 0,
0, (void**)&sHPETRegs);
if (sHPETArea < 0) {
put_module(B_ACPI_MODULE_NAME);
return sHPETArea;
}
return hpet_init();
}
void
uninit_driver(void)
{
hpet_set_enabled(false);
if (sHPETArea > 0)
delete_area(sHPETArea);
put_module(B_ACPI_MODULE_NAME);
}
const char**
publish_devices(void)
{
return hpet_name;
}
device_hooks*
find_device(const char* name)
{
return &hpet_hooks;
}
////////////////////////////////////////////////////////////////////////////////
// #pragma mark -
status_t
hpet_open(const char* name, uint32 flags, void** cookie)
{
*cookie = NULL;
if (sHPETRegs == NULL)
return B_NO_INIT;
if (atomic_add(&sOpenCount, 1) != 0) {
atomic_add(&sOpenCount, -1);
return B_BUSY;
}
hpet_timer_cookie* hpetCookie = (hpet_timer_cookie*)malloc(sizeof(hpet_timer_cookie));
int timerNumber = 2;
hpetCookie->number = timerNumber;
hpetCookie->sem = create_sem(0, "hpet_timer 2 sem");
set_sem_owner(hpetCookie->sem, B_SYSTEM_TEAM);
hpet_set_enabled(false);
hpet_init_timer(&sHPETRegs->timer[timerNumber]);
status_t status = hpet_configure_interrupt(&sHPETRegs->timer[timerNumber], &hpetCookie->irq);
if (status == B_OK)
status = install_io_interrupt_handler(hpetCookie->irq, &hpet_timer_interrupt, hpetCookie, 0);
if (status != B_OK)
dprintf("hpet_open(): cannot install interrupt handler: %s\n", strerror(status));
else
dprintf("hpet_open(): HPET timer uses irq %ld\n", hpetCookie->irq);
hpet_set_enabled(true);
*cookie = hpetCookie;
return status;
}
status_t
hpet_close(void* cookie)
{
if (sHPETRegs == NULL)
return B_NO_INIT;
atomic_add(&sOpenCount, -1);
hpet_timer_cookie* hpetCookie = (hpet_timer_cookie*)cookie;
dprintf("hpet_close (%d)\n", hpetCookie->number);
hpet_clear_hardware_timer(&sHPETRegs->timer[hpetCookie->number]);
remove_io_interrupt_handler(hpetCookie->irq, &hpet_timer_interrupt, hpetCookie);
return B_OK;
}
status_t
hpet_free(void* cookie)
{
if (sHPETRegs == NULL)
return B_NO_INIT;
hpet_timer_cookie* hpetCookie = (hpet_timer_cookie*)cookie;
delete_sem(hpetCookie->sem);
free(cookie);
return B_OK;
}
status_t
hpet_control(void* cookie, uint32 op, void* arg, size_t length)
{
hpet_timer_cookie* hpetCookie = (hpet_timer_cookie*)cookie;
status_t status = B_BAD_VALUE;
switch (op) {
case HPET_WAIT_TIMER:
{
bigtime_t value = *(bigtime_t*)arg;
dprintf("hpet: wait timer (%d) for %lld...\n", hpetCookie->number, value);
hpet_set_hardware_timer(value, &sHPETRegs->timer[hpetCookie->number]);
status = acquire_sem_etc(hpetCookie->sem, 1, B_CAN_INTERRUPT, B_INFINITE_TIMEOUT);
break;
}
default:
break;
}
return status;
}
ssize_t
hpet_read(void* cookie, off_t position, void* buffer, size_t* numBytes)
{
//hpet_timer_cookie* hpetCookie = (hpet_timer_cookie*)cookie;
*(uint64*)buffer = sHPETRegs->u0.counter64;
return sizeof(uint64);
}
ssize_t
hpet_write(void* cookie, off_t position, const void* buffer, size_t* numBytes)
{
*numBytes = 0;
return B_NOT_ALLOWED;
}
+118
View File
@@ -0,0 +1,118 @@
/*
* Copyright 2008, Dustin Howett, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_ARCH_x86_HPET_H
#define _KERNEL_ARCH_x86_HPET_H
#include <OS.h>
#include "arch_acpi.h"
/* All masks are 32 bits wide to represent relative bit locations */
/* Doing it this way is Required since the HPET only supports 32/64-bit aligned reads. */
/* Global Capability Register Masks */
#define HPET_CAP_MASK_REVID 0x00000000000000FFULL
#define HPET_CAP_MASK_NUMTIMERS 0x0000000000001F00ULL
#define HPET_CAP_MASK_WIDTH 0x0000000000002000ULL
#define HPET_CAP_MASK_LEGACY 0x0000000000008000ULL
#define HPET_CAP_MASK_VENDOR_ID 0x00000000FFFF0000ULL
#define HPET_CAP_MASK_PERIOD 0xFFFFFFFF00000000ULL
/* Retrieve Global Capabilities */
#define HPET_GET_REVID(regs) ((regs)->capabilities & HPET_CAP_MASK_REVID)
#define HPET_GET_NUM_TIMERS(regs) (((regs)->capabilities & HPET_CAP_MASK_NUMTIMERS) >> 8)
#define HPET_IS_64BIT(regs) (((regs)->capabilities & HPET_CAP_MASK_WIDTH) >> 13)
#define HPET_IS_LEGACY_CAPABLE(regs) (((regs)->capabilities & HPET_CAP_MASK_LEGACY) >> 15)
#define HPET_GET_VENDOR_ID(regs) (((regs)->capabilities & HPET_CAP_MASK_VENDOR_ID) >> 16)
#define HPET_GET_PERIOD(regs) (((regs)->capabilities & HPET_CAP_MASK_PERIOD) >> 32)
/* Global Config Register Masks */
#define HPET_CONF_MASK_ENABLED 0x00000001
#define HPET_CONF_MASK_LEGACY 0x00000002
/* Retrieve Global Configuration */
#define HPET_IS_ENABLED(regs) ((regs)->config & HPET_CONF_MASK_ENABLED)
#define HPET_IS_LEGACY(regs) (((regs)->config & HPET_CONF_MASK_LEGACY) >> 1)
/* Timer Configuration and Capabilities*/
#define HPET_CAP_TIMER_MASK 0xFFFFFFFF00000000ULL
#define HPET_CONF_TIMER_INT_ROUTE_MASK 0x3e00UL
#define HPET_CONF_TIMER_INT_ROUTE_SHIFT 9
#define HPET_CONF_TIMER_INT_TYPE 0x00000002UL
#define HPET_CONF_TIMER_INT_ENABLE 0x00000004UL
#define HPET_CONF_TIMER_TYPE 0x00000008UL
#define HPET_CONF_TIMER_VAL_SET 0x00000040UL
#define HPET_CONF_TIMER_32MODE 0x00000100UL
#define HPET_CONF_TIMER_FSB_ENABLE 0x00004000UL
#define HPET_CAP_TIMER_PER_INT 0x00000010UL
#define HPET_CAP_TIMER_SIZE 0x00000020UL
#define HPET_CAP_TIMER_FSB_INT_DEL 0x00008000UL
#define HPET_GET_CAP_TIMER_ROUTE(timer) (((timer)->config & HPET_CAP_TIMER_MASK) >> 32)
#define HPET_GET_CONF_TIMER_INT_ROUTE(timer) (((timer)->config & HPET_CONF_TIMER_INT_ROUTE_MASK) >> HPET_CONF_TIMER_INT_ROUTE_SHIFT)
#define ACPI_HPET_SIGNATURE "HPET"
struct hpet_timer {
/* Timer Configuration/Capability bits, Reversed because x86 is LSB */
volatile uint64 config;
/* R/W: Each bit represents one allowed interrupt for this timer. */
/* If interrupt 16 is allowed, bit 16 will be 1. */
union {
volatile uint64 comparator64; /* R/W: Comparator value */
volatile uint32 comparator32;
} u0; /* non-periodic mode: fires once when main counter = this comparator */
/* periodic mode: fires when timer reaches this value, is increased by the original value */
volatile uint64 fsb_route[2]; /* R/W: FSB Interrupt Route values */
};
struct hpet_regs {
volatile uint64 capabilities; /* Read Only */
volatile uint64 reserved1;
volatile uint64 config; /* R/W: Config Bits */
volatile uint64 reserved2;
/* Interrupt Status bits */
volatile uint64 interrupt_status; /* Interrupt Config bits for timers 0-31 */
/* Level Tigger: 0 = off, 1 = set by hardware, timer is active */
/* Edge Trigger: ignored */
/* Writing 0 will not clear these. Must write 1 again. */
volatile uint64 reserved3[25];
union {
volatile uint64 counter64; /* R/W */
volatile uint32 counter32;
} u0;
volatile uint64 reserved4;
volatile struct hpet_timer timer[1];
};
typedef struct acpi_hpet {
acpi_descriptor_header header; /* "HPET" signature and acpi header */
uint16 vendor_id;
uint8 legacy_capable : 1;
uint8 reserved1 : 1;
uint8 countersize : 1;
uint8 comparators : 5;
uint8 hw_revision;
struct hpet_addr {
uint8 address_space;
uint8 register_width;
uint8 register_offset;
uint8 reserved;
uint64 address;
} hpet_address;
uint8 number;
uint16 min_tick;
} _PACKED acpi_hpet;
#endif
@@ -0,0 +1,10 @@
#ifndef _HPET_H
#define _HPET_H
struct hpet_timer_cookie ;
#define HPET_WAIT_TIMER 0x0001
#endif
+16
View File
@@ -0,0 +1,16 @@
/*
* Copyright 2003-2010, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
#ifndef __INT_H
#define __INT_H
status_t reserve_io_interrupt_vectors(long count, long startVector);
status_t allocate_io_interrupt_vectors(long count, long *startVector);
void free_io_interrupt_vectors(long count, long startVector);
#endif /* __INT_H */
+33
View File
@@ -0,0 +1,33 @@
#ifndef _KERNEL_ARCH_x86_MSI_H
#define _KERNEL_ARCH_x86_MSI_H
#include <SupportDefs.h>
// address register
#define MSI_ADDRESS_BASE 0xfee00000
#define MSI_DESTINATION_ID_SHIFT 12
#define MSI_REDIRECTION 0x00000008
#define MSI_NO_REDIRECTION 0x00000000
#define MSI_DESTINATION_MODE_LOGICAL 0x00000004
#define MSI_DESTINATION_MODE_PHYSICAL 0x00000000
// data register
#define MSI_TRIGGER_MODE_EDGE 0x00000000
#define MSI_TRIGGER_MODE_LEVEL 0x00008000
#define MSI_LEVEL_DEASSERT 0x00000000
#define MSI_LEVEL_ASSERT 0x00004000
#define MSI_DELIVERY_MODE_FIXED 0x00000000
#define MSI_DELIVERY_MODE_LOWEST_PRIO 0x00000100
#define MSI_DELIVERY_MODE_SMI 0x00000200
#define MSI_DELIVERY_MODE_NMI 0x00000400
#define MSI_DELIVERY_MODE_INIT 0x00000500
#define MSI_DELIVERY_MODE_EXT_INT 0x00000700
void msi_init();
bool msi_supported();
status_t msi_allocate_vectors(uint8 count, uint8 *startVector,
uint64 *address, uint16 *data);
void msi_free_vectors(uint8 count, uint8 startVector);
#endif // _KERNEL_ARCH_x86_MSI_H