Revision 9: ChangeLog - sBestTimer -> sTimer, currentPriority -> bestPriority, timerPriority -> priority - Panic when a timer can't be used. - As a consequence of this, I removed the "if (sTimer != NULL)" checks from set/clear hardware timer, because we'll never get that far without sTimer. - Move apic's special init into its own function for arch_smp.c to call. Keep init around for the timer crawling code to not reject it and not have to write a special case into the loop. - Fix most () != (void) issues, except for interrupt handlers, because install_io_interrupt_handler and the like don't like (void) methods. On Fri, Jul 4, 2008 at 7:33 AM, Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> wrote: > "Dustin Howett" <alaricx@xxxxxxxxx> wrote: >> timers.diff Revision 8, ChangeLog >> - Priority is only used for module sorting. See note 1. >> - timer->init() now returns B_OK if the timer is initialized at the >> end of the method, or B_ERROR if it is not. >> The reason for this wording is that init will return B_OK if the >> timer is ALREADY initialized, but not perform >> further initialization or re-initialization. >> - APIC timer no longer needs a preinit, and will perform the >> preinitialization during init if it is not already done; >> no initialization variable is required, as sApicPtr is static and >> will be set by preinit and can be checked against. >> - Fixed some comment styles. > > Thanks! Looks good for the most part, I only have some minor > suggestions/comments left, but I would like to commit the work you've > done so far now :-) > >> +static int >> +hpet_get_prio() > [...] >> Index: headers/private/kernel/timer.h >> + int (*get_priority)(); > > As I already mentioned a few mails back, () means (...) in C - you > should explicitly use (void) instead. > >> + if (sBestTimer != NULL) { >> + dprintf("arch_init_timer: using %s timer.\n", sBestTimer-> >> name); >> + } else { >> + dprintf("arch_init_timer: No timers were found to be usable.\ >> n"); >> + // TODO: panic() ? I don't think we can do much without timers, >> + // and panicking here would have the advantage that we wouldn't >> + // have to check for sBestTimer != NULL in the functions above. >> + } > > Indeed panicking would be the right thing to do here. Also, I would > rename "sBestTimer" to "sTimer", since even though it might be the best > timer, it's also the only timer that's actually used. > >> arch_init_timer(kernel_args *args) > [...] >> + int currentPriority = -1; > > This I would rename to bestPriority, though, to separate it from > timerPriority :-) > And I would rename timerPriority to "priority". But those are just > suggestions, of course. > >> +static status_t >> +apic_init(struct kernel_args *args, int32 data) > [...] >> + /* If we're passed -1 for data (current CPU), the SMP code is not >> + calling us, so do not perform init. */ >> + if (data == -1) { >> + return B_OK; >> + } > > Since the SMP code needs to know the APIC timer personally, anyway, I > would separate these two from each other, remove the "data" field, and > have the SMP code call a dedicated init method not part of the > timer_info structure. > >> Notes >> [1] Priority does not seem to be required. The modules can just be >> given in priority order in sTimers instead of allocated numbers. >> I wanted to get your opinions on this (Stefano and Axel); can >> remove another unneeded method like get_priority() and all its calls. > > I prefer to have the priority explicit by function rather than having > it only implicit by order. That would also be something we would need > in case we ever use real modules for them :-) > > Bye, > Axel. > > > -- - DH
Index: src/system/kernel/arch/x86/arch_timer.c =================================================================== --- src/system/kernel/arch/x86/arch_timer.c (revision 26244) +++ src/system/kernel/arch/x86/arch_timer.c (working copy) @@ -32,60 +32,24 @@ # define TRACE(x) ; #endif +extern timer_info gPITTimer; +extern timer_info gAPICTimer; +extern timer_info gHPETTimer; -#define PIT_CLOCK_RATE 1193180 -#define PIT_MAX_TIMER_INTERVAL (0xffff * 1000000ll / PIT_CLOCK_RATE) +static timer_info *sTimers[] = { + &gPITTimer, + &gAPICTimer, + &gHPETTimer, + NULL +}; +static timer_info *sTimer = NULL; -static void -set_isa_hardware_timer(bigtime_t relative_timeout) -{ - uint16 next_event_clocks; - - if (relative_timeout <= 0) - next_event_clocks = 2; - else if (relative_timeout < PIT_MAX_TIMER_INTERVAL) - next_event_clocks = relative_timeout * PIT_CLOCK_RATE / 1000000; - else - next_event_clocks = 0xffff; - - out8(0x30, 0x43); - out8(next_event_clocks & 0xff, 0x40); - out8((next_event_clocks >> 8) & 0xff, 0x40); - - arch_int_enable_io_interrupt(0); -} - - -static void -clear_isa_hardware_timer(void) -{ - // mask out the timer - arch_int_disable_io_interrupt(0); -} - - -static int32 -isa_timer_interrupt(void *data) -{ - return timer_interrupt(); -} - - -int -apic_timer_interrupt(void) -{ - return timer_interrupt(); -} - - void arch_timer_set_hardware_timer(bigtime_t timeout) { TRACE(("arch_timer_set_hardware_timer: timeout %lld\n", timeout)); - // try the apic timer first - if (arch_smp_set_apic_timer(timeout) != B_OK) - set_isa_hardware_timer(timeout); + sTimer->set_hardware_timer(timeout); } @@ -93,21 +57,42 @@ arch_timer_clear_hardware_timer(void) { TRACE(("arch_timer_clear_hardware_timer\n")); - if (arch_smp_clear_apic_timer() != B_OK) - clear_isa_hardware_timer(); + sTimer->clear_hardware_timer(); } int arch_init_timer(kernel_args *args) { - //dprintf("arch_init_timer: entry\n"); + int i = 0; + int bestPriority = -1; + timer_info *timer = NULL; + cpu_status state = disable_interrupts(); - install_io_interrupt_handler(0, &isa_timer_interrupt, NULL, 0); - clear_isa_hardware_timer(); + for (i = 0; (timer = sTimers[i]) != NULL; i++) { + int priority; + if (timer->init(args) != B_OK) { + TRACE(("arch_init_timer: %s failed init. Skipping.\n", timer->name)); + continue; + } - // apic timer interrupt set up by smp code + priority = timer->get_priority(); + if (priority > bestPriority) { + bestPriority = priority; + sTimer = timer; + TRACE(("arch_init_timer: %s is now best timer module with prio %d.\n", timer->name, bestPriority)); + } + } + + if (sTimer != NULL) { + dprintf("arch_init_timer: using %s timer.\n", sTimer->name); + } else { + panic("No system timers were found usable.\n"); + } + + restore_interrupts(state); + return 0; } Index: src/system/kernel/arch/x86/timers/pit.h =================================================================== --- src/system/kernel/arch/x86/timers/pit.h (revision 0) +++ src/system/kernel/arch/x86/timers/pit.h (revision 0) @@ -0,0 +1,16 @@ +/* + * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_ARCH_x86_TIMERS_PIT_H +#define _KERNEL_ARCH_x86_TIMERS_PIT_H + +#include <SupportDefs.h> + +/* Method Prototypes */ +static int pit_get_prio(void); +static status_t pit_set_hardware_timer(bigtime_t relativeTimeout); +static status_t pit_clear_hardware_timer(void); +static status_t pit_init(struct kernel_args *args); + +#endif /* _KERNEL_ARCH_x86_TIMERS_PIT_H */ Index: src/system/kernel/arch/x86/timers/x86_pit.c =================================================================== --- src/system/kernel/arch/x86/timers/x86_pit.c (revision 0) +++ src/system/kernel/arch/x86/timers/x86_pit.c (revision 0) @@ -0,0 +1,89 @@ +/* + * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved. + * Copyright 2005, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx All rights reserved. + * Distributed under the terms of the MIT License. + * + * Copyright 2001, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ + +#include <timer.h> +#include <arch/x86/timer.h> + +#include <arch/int.h> +#include <arch/cpu.h> + +#include "pit.h" + +#define PIT_CLOCK_RATE 1193180 +#define PIT_MAX_TIMER_INTERVAL (0xffff * 1000000ll / PIT_CLOCK_RATE) + +static bool sPITTimerInitialized = false; +static int sPriority = 1; + +struct timer_info gPITTimer = { + "PIT", + &pit_get_prio, + &pit_set_hardware_timer, + &pit_clear_hardware_timer, + &pit_init +}; + + +static int +pit_get_prio(void) +{ + return sPriority; +} + + +static int32 +pit_timer_interrupt(void *data) +{ + return timer_interrupt(); +} + + +static status_t +pit_set_hardware_timer(bigtime_t relativeTimeout) +{ + uint16 nextEventClocks; + + if (relativeTimeout <= 0) + nextEventClocks = 2; + else if (relativeTimeout < PIT_MAX_TIMER_INTERVAL) + nextEventClocks = relativeTimeout * PIT_CLOCK_RATE / 1000000; + else + nextEventClocks = 0xffff; + + out8(0x30, 0x43); + out8(nextEventClocks & 0xff, 0x40); + out8((nextEventClocks >> 8) & 0xff, 0x40); + + arch_int_enable_io_interrupt(0); + return B_OK; +} + + +static status_t +pit_clear_hardware_timer(void) +{ + arch_int_disable_io_interrupt(0); + return B_OK; +} + + +static status_t +pit_init(struct kernel_args *args) +{ + if (sPITTimerInitialized) { + return B_OK; + } + + install_io_interrupt_handler(0, &pit_timer_interrupt, NULL, 0); + pit_clear_hardware_timer(); + + sPITTimerInitialized = true; + + return B_OK; +} Index: src/system/kernel/arch/x86/timers/apic.h =================================================================== --- src/system/kernel/arch/x86/timers/apic.h (revision 0) +++ src/system/kernel/arch/x86/timers/apic.h (revision 0) @@ -0,0 +1,17 @@ +/* + * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_ARCH_x86_TIMERS_APIC_H +#define _KERNEL_ARCH_x86_TIMERS_APIC_H + +#include <SupportDefs.h> + +/* Method Prototypes */ +static int apic_get_prio(void); +static status_t apic_set_hardware_timer(bigtime_t relativeTimeout); +static status_t apic_clear_hardware_timer(void); +static status_t apic_init(struct kernel_args *args); +status_t apic_smp_init_timer(struct kernel_args *args, int32 cpu); + +#endif /* _KERNEL_ARCH_x86_TIMERS_APIC_H */ Index: src/system/kernel/arch/x86/timers/x86_apic.c =================================================================== --- src/system/kernel/arch/x86/timers/x86_apic.c (revision 0) +++ src/system/kernel/arch/x86/timers/x86_apic.c (revision 0) @@ -0,0 +1,171 @@ +/* + * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved. + * Copyright 2002-2005, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx All rights reserved. + * Distributed under the terms of the MIT License. + * + * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. + * Distributed under the terms of the NewOS License. + */ + +#include <timer.h> +#include <arch/x86/timer.h> + +#include <int.h> +#include <arch/x86/smp_apic.h> + +#include <arch/cpu.h> +#include <arch/smp.h> + +#include "apic.h" + +static void *sApicPtr = NULL; +static uint32 sApicTicsPerSec = 0; +static int sPriority = 2; + +struct timer_info gAPICTimer = { + "APIC", + &apic_get_prio, + &apic_set_hardware_timer, + &apic_clear_hardware_timer, + &apic_init +}; + + +static int +apic_get_prio(void) +{ + return sPriority; +} + + +static uint32 +_apic_read(uint32 offset) +{ + return *(volatile uint32 *)((char *)sApicPtr + offset); +} + + +static void +_apic_write(uint32 offset, uint32 data) +{ + *(volatile uint32 *)((char *)sApicPtr + offset) = data; +} + + +static void +_apic_acknowledge_interrupt(void) +{ + _apic_write(APIC_EOI, 0); +} + + +static int32 +apic_timer_interrupt() +{ + _apic_acknowledge_interrupt(); + return timer_interrupt(); +} + + +#define MIN_TIMEOUT 1000 + +static status_t +apic_set_hardware_timer(bigtime_t relativeTimeout) +{ + cpu_status state; + uint32 config; + uint32 ticks; + + if (sApicPtr == NULL) + return B_ERROR; + + if (relativeTimeout < MIN_TIMEOUT) + relativeTimeout = MIN_TIMEOUT; + + // calculation should be ok, since it's going to be 64-bit + ticks = ((relativeTimeout * sApicTicsPerSec) / 1000000); + + state = disable_interrupts(); + + config = _apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer + _apic_write(APIC_LVT_TIMER, config); + + _apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer + + config = _apic_read(APIC_LVT_TIMER) & ~APIC_LVT_MASKED; // unmask the timer + _apic_write(APIC_LVT_TIMER, config); + + //TRACE_TIMER(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n", + // config, relativeTimeout, sApicTicsPerSec, ticks)); + + _apic_write(APIC_INITIAL_TIMER_COUNT, ticks); // start it up + + restore_interrupts(state); + + return B_OK; +} + + +static status_t +apic_clear_hardware_timer(void) +{ + cpu_status state; + uint32 config; + + if (sApicPtr == NULL) + return B_ERROR; + + state = disable_interrupts(); + + config = _apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer + _apic_write(APIC_LVT_TIMER, config); + + _apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer + + restore_interrupts(state); + return B_OK; +} + + +static status_t +apic_init(struct kernel_args *args) +{ + /* If we're in this method, arch_smp called the special init function. + Therefore, if we got here with sApicPtr NULL, there is no APIC! */ + if (sApicPtr == NULL) + return B_ERROR; + + return B_OK; +} + + +status_t +apic_smp_init_timer(struct kernel_args *args, int32 cpu) +{ + uint32 config; + + if (args->arch_args.apic == NULL) { + return B_ERROR; + } + + /* This is in place of apic_preinit; if we're not already initialized, + register the interrupt handler and set the pointers */ + if (sApicPtr == NULL) { + sApicPtr = (void *)args->arch_args.apic; + sApicTicsPerSec = args->arch_args.apic_time_cv_factor; + install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, &apic_timer_interrupt, NULL, B_NO_LOCK_VECTOR); + } + + /* setup timer */ + config = _apic_read(APIC_LVT_TIMER) & APIC_LVT_TIMER_MASK; + config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked + _apic_write(APIC_LVT_TIMER, config); + + _apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the clock + + config = _apic_read(APIC_TIMER_DIVIDE_CONFIG) & 0xfffffff0; + config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1 + _apic_write(APIC_TIMER_DIVIDE_CONFIG, config); + + return B_OK; +} Index: src/system/kernel/arch/x86/timers/hpet.h =================================================================== --- src/system/kernel/arch/x86/timers/hpet.h (revision 0) +++ src/system/kernel/arch/x86/timers/hpet.h (revision 0) @@ -0,0 +1,63 @@ +/* + * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_ARCH_x86_TIMERS_HPET_H +#define _KERNEL_ARCH_x86_TIMERS_HPET_H + +#include <SupportDefs.h> + +/* All masks are 64 bits wide to represent bit locations; + the HPET registers are 64 bits wide. */ + +/* Global Capability Register Masks */ +#define HPET_CAP_MASK_ID 0x00000000000000FF +#define HPET_CAP_MASK_NUMTIMERS 0x0000000000001F00 +#define HPET_CAP_MASK_WIDTH 0x0000000000002000 +#define HPET_CAP_MASK_LEGACY 0x0000000000008000 +#define HPET_CAP_MASK_VENDOR_ID 0x00000000FFFF0000 +#define HPET_CAP_MASK_PERIOD 0xFFFFFFFF00000000 + +/* Convenience macros for Capability masks */ +#define HPET_GET_ID(regs) ((regs)->caps & HPET_CAP_MASK_ID) +#define HPET_GET_NUM_TIMERS(regs) (((regs)->caps & HPET_CAP_MASK_NUMTIMERS) >> 8) +#define HPET_IS_64BIT_CAPABLE(regs) (((regs)->caps & HPET_CAP_MASK_WIDTH) >> 13) +#define HPET_IS_LEGACY_CAPABLE(regs) (((regs)->caps & HPET_CAP_MASK_LEGACY) >> 15) +#define HPET_GET_VENDOR_ID(regs) (((regs)->caps & HPET_CAP_MASK_VENDOR_ID) >> 16) +#define HPET_GET_PERIOD(regs) (((regs)->caps & HPET_CAP_MASK_PERIOD) >> 32) + +/* Global Configuration Masks */ +#define HPET_CONF_MASK_ENABLED 0x0000000000000001 +#define HPET_CONF_MASK_LEGACY 0x0000000000000002 + +/* Convenience macros for Config masks */ +#define HPET_IS_ENABLED(regs) ((regs)->config & HPET_CONF_MASK_ENABLED) +#define HPET_IS_LEGACY(regs) (((regs)->config & HPET_CONF_MASK_LEGACY) >> 1) + +struct hpet_timer { + uint64 config; /* Timer configuration and capabilities */ + uint64 comparator; /* Comparator value */ + uint64 introute; /* FSB Interrupt Routing */ + uint64 reserved; +}; + + +struct hpet_regs { + uint64 caps; /* HPET Capabilities and ID */ + uint64 reserved1; + uint64 config; /* General Configuration */ + uint64 reserved2; + uint64 intstatus; /* General Interrupt Status */ + uint8 reserved3[200]; + uint64 mainvalue; /* Main Counter Value */ + uint64 reserved4; + struct hpet_timer timers[1]; /* Timers */ +}; + +/* Method prototypes */ +static int hpet_get_prio(void); +static status_t hpet_set_hardware_timer(bigtime_t relativeTimeout); +static status_t hpet_clear_hardware_timer(void); +static status_t hpet_init(struct kernel_args *args); + +#endif /* _KERNEL_ARCH_x86_TIMERS_HPET_H */ Index: src/system/kernel/arch/x86/timers/x86_hpet.c =================================================================== --- src/system/kernel/arch/x86/timers/x86_hpet.c (revision 0) +++ src/system/kernel/arch/x86/timers/x86_hpet.c (revision 0) @@ -0,0 +1,90 @@ + +/* + * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved. + * Distributed under the terms of the MIT License. + */ + +#include <timer.h> +#include <arch/x86/timer.h> + +#include "hpet.h" + +static int32 sHPETAddr; +static struct hpet_regs *sHPETRegs; +static int sPriority = 3; + +struct timer_info gHPETTimer = { + "HPET", + &hpet_get_prio, + &hpet_set_hardware_timer, + &hpet_clear_hardware_timer, + &hpet_init +}; + + +static int +hpet_get_prio(void) +{ + return sPriority; +} + + +/* 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 int +hpet_set_enabled(struct hpet_regs *regs, bool enabled) +{ + if (enabled) + regs->config |= HPET_CONF_MASK_ENABLED; + else + regs->config &= ~HPET_CONF_MASK_ENABLED; + return B_OK; +} + + +static int +hpet_set_legacy(struct hpet_regs *regs, bool enabled) +{ + if (!HPET_IS_LEGACY_CAPABLE(regs)) + return B_NOT_SUPPORTED; + + if (enabled) + regs->config |= HPET_CONF_MASK_LEGACY; + else + regs->config &= ~HPET_CONF_MASK_LEGACY; + return B_OK; +} + + +static int32 +hpet_timer_interrupt(void) +{ + 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; +} Index: src/system/kernel/arch/x86/Jamfile =================================================================== --- src/system/kernel/arch/x86/Jamfile (revision 26244) +++ src/system/kernel/arch/x86/Jamfile (working copy) @@ -4,18 +4,20 @@ # for syscall_numbers.h SubDirHdrs $(HAIKU_TOP) src add-ons kernel bus_managers ps2 ; SubDirHdrs $(SUBDIR) $(DOTDOT) generic ; +SubDirHdrs $(SUBDIR) timers ; UsePrivateKernelHeaders ; SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) generic ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) timers ] ; + KernelMergeObject kernel_arch_x86.o : arch_commpage.cpp arch_cpu.c arch_debug.cpp arch_debug_console.c arch_elf.c - arch_hpet.c arch_int.c arch_platform.c # arch_selector.c @@ -35,6 +37,10 @@ cpuid.S syscall.S vm86.cpp + + x86_pit.c + x86_apic.c + x86_hpet.c generic_vm_physical_page_mapper.cpp : Index: src/system/kernel/arch/x86/arch_smp.c =================================================================== --- src/system/kernel/arch/x86/arch_smp.c (revision 26244) +++ src/system/kernel/arch/x86/arch_smp.c (working copy) @@ -17,6 +17,8 @@ #include <arch/vm.h> #include <arch/smp.h> +#include <timer.h> + #include <arch/x86/smp_priv.h> #include <arch/x86/smp_apic.h> #include <arch/x86/timer.h> @@ -39,25 +41,15 @@ # define TRACE_TIMER(x) ; #endif +extern timer_info gAPICTimer; static void *apic = NULL; static uint32 cpu_apic_id[B_MAX_CPU_COUNT] = {0, 0}; static uint32 cpu_os_id[B_MAX_CPU_COUNT] = {0, 0}; static uint32 cpu_apic_version[B_MAX_CPU_COUNT] = {0, 0}; static void *ioapic = NULL; -static uint32 apic_timer_tics_per_sec = 0; - static int32 -i386_timer_interrupt(void *data) -{ - arch_smp_ack_interrupt(); - - return apic_timer_interrupt(); -} - - -static int32 i386_ici_interrupt(void *data) { // genuine inter-cpu interrupt @@ -147,17 +139,8 @@ } #endif - /* setup timer */ - config = apic_read(APIC_LVT_TIMER) & APIC_LVT_TIMER_MASK; - config |= 0xfb | APIC_LVT_MASKED; // vector 0xfb, timer masked - apic_write(APIC_LVT_TIMER, config); + apic_smp_init_timer(args, cpu); - apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the clock - - config = apic_read(APIC_TIMER_DIVIDE_CONFIG) & 0xfffffff0; - config |= APIC_TIMER_DIVIDE_CONFIG_1; // clock division by 1 - apic_write(APIC_TIMER_DIVIDE_CONFIG, config); - /* setup error vector to 0xfe */ config = (apic_read(APIC_LVT_ERROR) & 0xffffff00) | 0xfe; apic_write(APIC_LVT_ERROR, config); @@ -185,7 +168,6 @@ memcpy(cpu_apic_id, args->arch_args.cpu_apic_id, sizeof(args->arch_args.cpu_apic_id)); memcpy(cpu_os_id, args->arch_args.cpu_os_id, sizeof(args->arch_args.cpu_os_id)); memcpy(cpu_apic_version, args->arch_args.cpu_apic_version, sizeof(args->arch_args.cpu_apic_version)); - apic_timer_tics_per_sec = args->arch_args.apic_time_cv_factor; // setup regions that represent the apic & ioapic map_physical_memory("local apic", (void *)args->arch_args.apic_phys, B_PAGE_SIZE, @@ -197,7 +179,6 @@ arch_smp_per_cpu_init(args, 0); // I/O interrupts start at ARCH_INTERRUPT_BASE, so all interrupts are shifted - install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE, &i386_timer_interrupt, NULL, B_NO_LOCK_VECTOR); install_io_interrupt_handler(0xfd - ARCH_INTERRUPT_BASE, &i386_ici_interrupt, NULL, B_NO_LOCK_VECTOR); install_io_interrupt_handler(0xfe - ARCH_INTERRUPT_BASE, &i386_smp_error_interrupt, NULL, B_NO_LOCK_VECTOR); install_io_interrupt_handler(0xff - ARCH_INTERRUPT_BASE, &i386_spurious_interrupt, NULL, B_NO_LOCK_VECTOR); @@ -268,63 +249,3 @@ { apic_write(APIC_EOI, 0); } - -#define MIN_TIMEOUT 1000 - -status_t -arch_smp_set_apic_timer(bigtime_t relativeTimeout) -{ - cpu_status state; - uint32 config; - uint32 ticks; - - if (apic == NULL) - return B_ERROR; - - if (relativeTimeout < MIN_TIMEOUT) - relativeTimeout = MIN_TIMEOUT; - - // calculation should be ok, since it's going to be 64-bit - ticks = ((relativeTimeout * apic_timer_tics_per_sec) / 1000000); - - state = disable_interrupts(); - - config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer - apic_write(APIC_LVT_TIMER, config); - - apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer - - config = apic_read(APIC_LVT_TIMER) & ~APIC_LVT_MASKED; // unmask the timer - apic_write(APIC_LVT_TIMER, config); - - TRACE_TIMER(("arch_smp_set_apic_timer: config 0x%lx, timeout %Ld, tics/sec %lu, tics %lu\n", - config, relativeTimeout, apic_timer_tics_per_sec, ticks)); - - apic_write(APIC_INITIAL_TIMER_COUNT, ticks); // start it up - - restore_interrupts(state); - - return B_OK; -} - - -status_t -arch_smp_clear_apic_timer(void) -{ - cpu_status state; - uint32 config; - - if (apic == NULL) - return B_ERROR; - - state = disable_interrupts(); - - config = apic_read(APIC_LVT_TIMER) | APIC_LVT_MASKED; // mask the timer - apic_write(APIC_LVT_TIMER, config); - - apic_write(APIC_INITIAL_TIMER_COUNT, 0); // zero out the timer - - restore_interrupts(state); - return B_OK; -} - Index: src/system/kernel/arch/x86/arch_hpet.c =================================================================== --- src/system/kernel/arch/x86/arch_hpet.c (working copy) +++ src/system/kernel/arch/x86/arch_hpet.c (working copy) @@ -1,6 +0,0 @@ -/* - * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved. - * Distributed under the terms of the MIT License. - */ - -#include <arch/x86/arch_hpet.h> Index: headers/private/kernel/arch/x86/arch_hpet.h =================================================================== --- headers/private/kernel/arch/x86/arch_hpet.h (working copy) +++ headers/private/kernel/arch/x86/arch_hpet.h (working copy) @@ -1,49 +0,0 @@ -/* - * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved. - * Distributed under the terms of the MIT License. - */ -#ifndef _KERNEL_ARCH_x86_HPET_H -#define _KERNEL_ARCH_x86_HPET_H - -#include <types.h> - -/* All masks are 64 bits wide to represent bit locations; - the HPET registers are 64 bits wide. */ - -/* Global Capability Register Masks */ -#define HPET_CAP_MASK_ID 0x00000000000000FF -#define HPET_CAP_MASK_NUMTIMERS 0x0000000000001F00 -#define HPET_CAP_MASK_WIDTH 0x0000000000002000 -#define HPET_CAP_MASK_LEGACY 0x0000000000008000 -#define HPET_CAP_MASK_VENDOR_ID 0x00000000FFFF0000 -#define HPET_CAP_MASK_PERIOD 0xFFFFFFFF00000000 - -/* Retrieve Global Capabilities */ -#define HPET_GET_ID(regs) ((regs)->caps & HPET_CAP_MASK_ID) -#define HPET_GET_NUM_TIMERS(regs) (((regs)->caps & HPET_CAP_MASK_NUMTIMERS) >> 8) -#define HPET_IS_64BIT_CAPABLE(regs) (((regs)->caps & HPET_CAP_MASK_WIDTH) >> 13) -#define HPET_IS_LEGACY_CAPABLE(regs) (((regs)->caps & HPET_CAP_MASK_LEGACY) >> 15) -#define HPET_GET_VENDOR_ID(regs) (((regs)->caps & HPET_CAP_MASK_VENDOR_ID) >> 16) -#define HPET_GET_PERIOD(regs) (((regs)->caps & HPET_CAP_MASK_PERIOD) >> 32) - -struct hpet_timer { - uint64 config; /* Timer configuration and capabilities */ - uint64 comparator; /* Comparator value */ - uint64 introute; /* FSB Interrupt Routing */ - uint64 reserved; -}; - - -struct hpet_regs { - uint64 caps; /* HPET Capabilities and ID */ - uint64 reserved1; - uint64 config; /* General Configuration */ - uint64 reserved2; - uint64 intstatus; /* General Interrupt Status */ - uint8 reserved3[200]; - uint64 mainvalue; /* Main Counter Value */ - uint64 reserved4; - struct hpet_timer timers[1]; /* Timers */ -}; - -#endif Index: headers/private/kernel/arch/x86/timer.h =================================================================== --- headers/private/kernel/arch/x86/timer.h (revision 26244) +++ headers/private/kernel/arch/x86/timer.h (working copy) @@ -2,10 +2,12 @@ ** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ -#ifndef _NEWOS_KERNEL_ARCH_I386_TIMER -#define _NEWOS_KERNEL_ARCH_I386_TIMER +#ifndef _KERNEL_ARCH_X86_TIMER +#define _KERNEL_ARCH_X86_TIMER -int apic_timer_interrupt(void); +#define ISA_TIMER_MODULE_NAME "timers/x86/isa/v1" +#define APIC_TIMER_MODULE_NAME "timers/x86/apic/v1" +#define HPET_TIMER_MODULE_NAME "timers/x86/hpet/v1" #endif Index: headers/private/kernel/timer.h =================================================================== --- headers/private/kernel/timer.h (revision 26244) +++ headers/private/kernel/timer.h (working copy) @@ -18,6 +18,18 @@ #define B_TIMER_ACQUIRE_THREAD_LOCK 0x8000 #define B_TIMER_FLAGS B_TIMER_ACQUIRE_THREAD_LOCK +/* Timer info structure */ +struct timer_info { + char *name; + int (*get_priority)(void); + status_t (*set_hardware_timer)(bigtime_t timeout); + status_t (*clear_hardware_timer)(void); + status_t (*init)(struct kernel_args *args); +}; + +typedef struct timer_info timer_info; + + /* kernel functions */ status_t timer_init(struct kernel_args *); int32 timer_interrupt(void);