[haiku-gsoc] New timer patch (again) (Was: Re: First timer.diff (from private e-mails))

I have yet another patch for consideration (sending to haiku-gsoc so
all discussion on it can get captured here).

I haven't tried it on native hardware but it boots in qemu (in both
uniprocessor mode and multiprocessor mode, the PIT and APIC timers get
used)

It addresses many of Axel's concerns (anything that remains, please let me know)

On Wed, Jun 18, 2008 at 10:58 PM, Dustin Howett <alaricx@xxxxxxxxx> wrote:
> My main concern with implementing something like gX86SwapFPUFunc() is
> that there are multiple timer methods that need to be switched out,
> which is why I opted instead for a structure; i instinctively chose
> the module structure because it provided what I needed.
>
> I'm not sure how exactly to go about this then. Should I just use a
> standard structure full of function pointers, with a timer name, or
> should I really set each function individually.
>
> Everything else (coding style, copyrights, paths, etc.) has been resolved.
>
> I would not be opposed to somehow moving ACPI into the kernel to help
> with HPET (need to talk to Korli, i imagine).. otherwise, I'm not
> quite sure how to implement the timers as true modules. Moving the
> module init code earlier in the kernel (before timers) may not be the
> best way to go (speaking from an uneducated-on-this-topic standpoint,
> of course) only because scheduling is needed for modules (I believe
> Stefano mentioned) and it would be a good deal of work.
>
> Currently trying to find a good way to do it and overcome the booting
> issues having them as "modules" brought.
>
> On Tue, Jun 17, 2008 at 11:40 AM, Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> wrote:
>> Hi Dustin,
>>
>> "Dustin Howett" <alaricx@xxxxxxxxx> wrote:
>>> * Will adapt to the coding style
>>> * As for relative_timeout, i was reusing the variable names from
>>> arch_timer.c
>>
>> I guessed so, but I wanted to mentioning it anyway, as there were other
>> example of new code, too.
>>
>>> * I was intending to copy over the copyrights
>>> * Since timer_module_info is missing, i note that you have an older
>>> version of the patch.
>>
>> I only got what Stefano sent me.
>> BTW would you mind to move any further discussion to the gsoc mailing
>> list? Coding style problems and the like are probably are problem of
>> everyone :-)
>>
>>> * I had something in mind that would make module.cpp build; each
>>> arch's arch_timer would have a list of the timers it supports.
>>
>> That would work. Anyway, you made a specific comment about another
>> architecture that would need such a timer architecture - which one were
>> you referring to?
>>
>>> * Will look into making them non-modular. I realize this is a better
>>> decision and will rectify the rest of the things you've listed.
>>
>> At least it's a better decision for now. If not possible otherwise, I
>> also wouldn't mind of moving the ACPI module (or some core
>> functionality of it) into the kernel.
>>
>>> I also need to fix the booting issues they cause. I sent the patch
>>> only for review anyway- actually, for exactly this kind of thing.
>>> Thank you very much for explaining what was wrong :)
>>
>> Glad to help :-)
>> If you have any questions, don't hesitate, I'm just away over the
>> weekend, but I'll be back on Monday; I don't remember exactly when
>> Stefano will return.
>>
>> Bye,
>>   Axel.
>>
>>
>
>
>
> --
>
> - DH
>



--

- DH
Index: src/system/kernel/arch/x86/arch_timer.c
===================================================================
--- src/system/kernel/arch/x86/arch_timer.c     (revision 26018)
+++ src/system/kernel/arch/x86/arch_timer.c     (working copy)
@@ -25,88 +25,85 @@
 
 #include "interrupts.h"
 
-//#define TRACE_TIMER
+#define TRACE_TIMER
 #ifdef TRACE_TIMER
 #      define TRACE(x) dprintf x
 #else
 #      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 *timers[] = {
+       &gPITTimer,
+       &gAPICTimer,
+       &gHPETTimer,
+       NULL
+};
 
+static timer_info *sBestTimer = NULL;
 
-static void
-set_isa_hardware_timer(bigtime_t relative_timeout)
+void
+arch_timer_set_hardware_timer(bigtime_t 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);
+//     TRACE(("arch_timer_set_hardware_timer: timeout %lld\n", timeout));
+       if(sBestTimer != NULL)
+               sBestTimer->set_hardware_timer(timeout);
 }
 
 
-static void
-clear_isa_hardware_timer(void)
+void
+arch_timer_clear_hardware_timer(void)
 {
-       // mask out the timer
-       arch_int_disable_io_interrupt(0);
+//     TRACE(("arch_timer_clear_hardware_timer\n"));
+       if(sBestTimer != NULL)
+               sBestTimer->clear_hardware_timer();
 }
 
 
-static int32
-isa_timer_interrupt(void *data)
-{
-       return timer_interrupt();
-}
-
-
 int
-apic_timer_interrupt(void)
+arch_init_timer(kernel_args *args)
 {
-       return timer_interrupt();
-}
+       int cur_timer = 0;
+       int cur_prio = -1;
+       char cur_best_name[B_FILE_NAME_LENGTH];
 
+       cpu_status state = disable_interrupts();
 
-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);
-}
+       while(true) {
+               timer_info *timer = timers[cur_timer++];
 
+               if(timer == NULL) break;
 
-void
-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();
-}
+               if(!timer->initialized) {
+                       TRACE(("arch_init_timer: %s was not initialized. 
Attempting.\n", timer->name));
+                       if(timer->init(args, 1) != B_OK) {
+                               TRACE(("arch_init_timer: %s would not 
initialize. Skipping.\n", timer->name));
+                               continue;
+                       }
+               }
 
+               if(!timer->initialized) {
+                       TRACE(("arch_init_timer: %s still not valid but didn't 
fail init..\n", timer->name));
+                       continue;
+               }
 
-int
-arch_init_timer(kernel_args *args)
-{
-       //dprintf("arch_init_timer: entry\n");
+               if(timer->priority > cur_prio) {
+                       cur_prio = timer->priority;
+                       sBestTimer = timer;
+                       TRACE(("arch_init_timer: %s is now best timer module 
with prio %d.\n", timer->name, cur_prio));
+               }
+       }
 
-       install_io_interrupt_handler(0, &isa_timer_interrupt, NULL, 0);
-       clear_isa_hardware_timer();
+       if(sBestTimer != NULL) {
+               TRACE(("arch_init_timer: Best timer is %s\n", 
sBestTimer->name));
+       } else {
+               TRACE(("arch_init_timer: NO VIABLE TIMERS?!\n"));
+       }
 
-       // apic timer interrupt set up by smp code
+       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,15 @@
+/*
+ * 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 status_t pit_set_hardware_timer(bigtime_t relativeTimeout);
+static status_t pit_clear_hardware_timer();
+static status_t pit_init(struct kernel_args *args, int32 data);
+
+#endif
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,79 @@
+/*
+ * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
+ * Distributed under the terms of the MIT License.
+
+ * 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 sPITTimerIsValid = false;
+
+struct timer_info gPITTimer = {
+       "PIT",
+       false,
+       1,
+       &pit_set_hardware_timer,
+       &pit_clear_hardware_timer,
+       &pit_init,
+       NULL,
+};
+
+
+static int32
+pit_timer_interrupt(void *data)
+{
+       return timer_interrupt();
+}
+
+
+static status_t
+pit_set_hardware_timer(bigtime_t relativeTimeout)
+{
+       uint16 next_event_clocks;
+
+       if (relativeTimeout <= 0)
+               next_event_clocks = 2;
+       else if (relativeTimeout < PIT_MAX_TIMER_INTERVAL)
+               next_event_clocks = relativeTimeout * 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);
+       return B_OK;
+}
+
+
+static status_t
+pit_clear_hardware_timer()
+{
+       arch_int_disable_io_interrupt(0);
+       return B_OK;
+}
+
+
+static status_t
+pit_init(struct kernel_args *args, int32 data)
+{
+       install_io_interrupt_handler(0, &pit_timer_interrupt, NULL, 0);
+       pit_clear_hardware_timer();
+       gPITTimer.initialized = 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,16 @@
+/*
+ * 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 status_t apic_set_hardware_timer(bigtime_t relativeTimeout);
+static status_t apic_clear_hardware_timer();
+static status_t apic_init(struct kernel_args *args, int32 data);
+static void apic_preinit(struct kernel_args *args);
+
+#endif
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,158 @@
+/*
+ * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * 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 bool sInit = false;
+
+struct timer_info gAPICTimer = {
+       "APIC",
+       false,
+       2,
+       &apic_set_hardware_timer,
+       &apic_clear_hardware_timer,
+       &apic_init,
+       &apic_preinit,
+};
+
+
+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_ack_interrupt(void)
+{
+       _apic_write(APIC_EOI, 0);
+}
+
+
+static int32
+apic_timer_interrupt()
+{
+       _apic_ack_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()
+{
+       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, int32 data)
+{
+       uint32 config;
+
+       if(sApicPtr == NULL)
+               return B_ERROR;
+
+       /* 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);
+
+       gAPICTimer.initialized = true;
+       return B_OK;
+}
+
+
+static void
+apic_preinit(struct kernel_args *args)
+{
+       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);
+}
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,62 @@
+/*
+ * 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 status_t hpet_set_hardware_timer(bigtime_t relativeTimeout);
+static status_t hpet_clear_hardware_timer();
+static status_t hpet_init(struct kernel_args *args, int32 data);
+
+#endif
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,75 @@
+/*
+ * 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;
+
+struct timer_info gHPETTimer = {
+       "HPET",
+       false,
+       3,
+       &hpet_set_hardware_timer,
+       &hpet_clear_hardware_timer,
+       &hpet_init,
+       NULL
+};
+
+
+// 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 == true) 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 == true) regs->config |= HPET_CONF_MASK_LEGACY;
+       else regs->config &= ~HPET_CONF_MASK_LEGACY;
+       return B_OK;
+}
+
+
+static int32
+hpet_timer_interrupt()
+{
+       return timer_interrupt();
+}
+
+
+static status_t
+hpet_set_hardware_timer(bigtime_t relative_timeout)
+{
+       return B_ERROR;
+}
+
+
+static status_t
+hpet_clear_hardware_timer()
+{
+       return B_ERROR;
+}
+
+
+static status_t
+hpet_init(struct kernel_args *args, int32 data)
+{
+       // hpet_acpi_probe() through a similar "scan spots" table to that of 
smp.cpp.
+       // Seems to be the most elegant solution right now.
+       return B_ERROR;
+}
Index: src/system/kernel/arch/x86/Jamfile
===================================================================
--- src/system/kernel/arch/x86/Jamfile  (revision 26018)
+++ src/system/kernel/arch/x86/Jamfile  (working copy)
@@ -4,11 +4,14 @@
        # 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
@@ -35,6 +38,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 26018)
+++ 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);
+       gAPICTimer.init(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);
@@ -179,13 +162,13 @@
        TRACE(("arch_smp_init: entry\n"));
 
        if (args->num_cpus > 1) {
+
                // setup some globals
                apic = (void *)args->arch_args.apic;
                ioapic = (void *)args->arch_args.ioapic;
                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,
@@ -193,11 +176,12 @@
                map_physical_memory("ioapic", (void 
*)args->arch_args.ioapic_phys, B_PAGE_SIZE,
                        B_EXACT_ADDRESS, B_KERNEL_READ_AREA | 
B_KERNEL_WRITE_AREA, &ioapic);
 
+               gAPICTimer.preinit(args);
+
                // set up the local apic on the boot cpu
                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 +252,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      (revision 26018)
+++ src/system/kernel/arch/x86/arch_hpet.c      (working copy)
@@ -2,5 +2,45 @@
  * Copyright 2008, Dustin Howett, dustin.howett@xxxxxxxxxx All rights reserved.
  * Distributed under the terms of the MIT License.
  */
+/*
+#include <kernel.h>
+#include <boot/stage2.h>
 
 #include <arch/x86/arch_hpet.h>
+
+static int32 hpet_phys_addr;
+static struct hpet_regs *hpet_register;
+
+// 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 == true) 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 == true) regs->config |= HPET_CONF_MASK_LEGACY;
+       else regs->config &= ~HPET_CONF_MASK_LEGACY;
+       return B_OK;
+}
+
+
+int
+arch_init_hpet(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.
+
+       // Return EOPNOTSUPP for the time being.
+       return B_NOT_SUPPORTED;
+}
+*/
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 26018)
+++ 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 26018)
+++ headers/private/kernel/timer.h      (working copy)
@@ -7,6 +7,7 @@
 
 
 #include <KernelExport.h>
+#include <module.h>
 
 
 #ifdef __cplusplus
@@ -18,6 +19,21 @@
 #define B_TIMER_ACQUIRE_THREAD_LOCK    0x8000
 #define B_TIMER_FLAGS                          B_TIMER_ACQUIRE_THREAD_LOCK
 
+/* Timer info structure */
+struct timer_info
+{
+       char *name;
+       bool initialized;
+       int priority;
+       status_t (*set_hardware_timer)(bigtime_t timeout);
+       status_t (*clear_hardware_timer)();
+       status_t (*init)(struct kernel_args *args, int32 data);
+       void (*preinit)(struct kernel_args *args);
+};
+
+typedef struct timer_info timer_info;
+
+
 /* kernel functions */
 status_t timer_init(struct kernel_args *);
 int32 timer_interrupt(void);

Other related posts: