The actual implementation of HPET timers (not used yet, as it seems not to work correctly), by Dustin Howett (GSOC)

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27135 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini
2008-08-22 09:34:19 +00:00
parent 2f2ba71fab
commit dcd8c085ed
+106 -30
View File
@@ -1,4 +1,3 @@
/*
* Copyright 2008, Dustin Howett, [email protected]. All rights reserved.
* Distributed under the terms of the MIT License.
@@ -8,9 +7,21 @@
#include <arch/x86/timer.h>
#include <arch/x86/arch_hpet.h>
#include <boot/kernel_args.h>
#include <arch/int.h>
#include <arch/cpu.h>
#include "hpet.h"
static int32 sHPETAddr;
#define TRACE_HPET
#ifdef TRACE_HPET
#define TRACE(x) dprintf x
#else
#define TRACE(x) ;
#endif
static uint32 sHPETAddr;
static struct hpet_regs *sHPETRegs;
struct timer_info gHPETTimer = {
@@ -29,9 +40,60 @@ hpet_get_prio(void)
}
/* TODO: Implement something similar to smp_acpi_probe from boot/.../smp.cpp-
we need to get the hpet base address without talking to the acpi module,
because there's no guarantee that it's actually present at this early point. */
static int32
hpet_timer_interrupt(struct hpet_timer *timer)
{
return timer_interrupt();
}
static status_t
hpet_set_hardware_timer(bigtime_t relativeTimeout)
{
cpu_status state;
uint64 timerValue;
//dprintf("disabling interrupts\n");
state = disable_interrupts();
//dprintf("getting value\n");
timerValue = relativeTimeout;
timerValue *= 1000000;
timerValue /= sHPETRegs->period;
//dprintf("adding hpet counter value\n");
timerValue += sHPETRegs->counter;
//dprintf("setting value %d, cur is %d\n", timerValue, sHPETRegs->counter);
sHPETRegs->timer2.comparator = timerValue;
// Clear the interrupt (set to 0)
//dprintf("clearing interrupts\n");
sHPETRegs->timer2.config &= (~31 << 9);
// Non-periodic mode, edge triggered
//dprintf("edge mode\n");
sHPETRegs->timer2.config &= ~(0x8 & 0x2);
// Enable timer
//dprintf("enable\n");
sHPETRegs->timer2.config |= 0x4;
//dprintf("reenable interrupts\n");
restore_interrupts(state);
return B_OK;
}
static status_t
hpet_clear_hardware_timer(void)
{
// Disable timer
sHPETRegs->timer2.config &= ~0x4;
return B_OK;
}
static int
hpet_set_enabled(struct hpet_regs *regs, bool enabled)
@@ -47,8 +109,8 @@ hpet_set_enabled(struct hpet_regs *regs, bool enabled)
static int
hpet_set_legacy(struct hpet_regs *regs, bool enabled)
{
if (!HPET_IS_LEGACY_CAPABLE(regs))
return B_NOT_SUPPORTED;
// if (!HPET_IS_LEGACY_CAPABLE(regs))
// return B_NOT_SUPPORTED;
if (enabled)
regs->config |= HPET_CONF_MASK_LEGACY;
@@ -58,33 +120,47 @@ hpet_set_legacy(struct hpet_regs *regs, bool enabled)
}
static int32
hpet_timer_interrupt(void *data)
{
return timer_interrupt();
}
static status_t
hpet_set_hardware_timer(bigtime_t relative_timeout)
{
return B_ERROR;
}
static status_t
hpet_clear_hardware_timer(void)
{
return B_ERROR;
}
static status_t
hpet_init(struct kernel_args *args)
{
/* hpet_acpi_probe() through a similar "scan spots" table to that of smp.cpp.
Seems to be the most elegant solution right now. */
/* There is no hpet support proper, so error out on init */
return B_ERROR;
if (args->arch_args.hpet == NULL) {
return B_ERROR;
}
if (sHPETRegs == NULL) {
sHPETRegs = (struct hpet_regs *)args->arch_args.hpet;
if (map_physical_memory("hpet", (void *)args->arch_args.hpet_phys,
B_PAGE_SIZE, B_EXACT_ADDRESS, B_KERNEL_READ_AREA |
B_KERNEL_WRITE_AREA, (void **)&sHPETRegs) < B_OK) {
// Would it be better to panic here?
dprintf("hpet_init: Failed to map memory for the HPET registers.");
return B_ERROR;
}
}
TRACE(("hpet_init: HPET is at %x. Vendor ID: %x.\n", sHPETRegs, HPET_GET_VENDOR_ID(sHPETRegs)));
/* There is no hpet legacy support, so error out on init */
if (!HPET_IS_LEGACY_CAPABLE(sHPETRegs)) {
dprintf("hpet_init: HPET does support legacy mode. Skipping.\n");
return B_ERROR;
}
hpet_set_legacy(sHPETRegs, true);
TRACE(("hpet_init: HPET does%s support legacy mode.\n", HPET_IS_LEGACY_CAPABLE(sHPETRegs) ? "" : " not"));
TRACE(("hpet_init: HPET supports %d timers, and is %s bits wide.\n", HPET_GET_NUM_TIMERS(sHPETRegs) + 1, HPET_IS_64BIT(sHPETRegs) ? "64" : "32"));
if (HPET_GET_NUM_TIMERS(sHPETRegs) < 2) {
dprintf("hpet_init: HPET does not have at least 3 timers. Skipping.\n");
return B_ERROR;
}
install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, &hpet_timer_interrupt, NULL, B_NO_LOCK_VECTOR);
install_io_interrupt_handler(0, &hpet_timer_interrupt, NULL, B_NO_LOCK_VECTOR);
hpet_set_enabled(sHPETRegs, true);
return B_OK;
}