[haiku-commits] r35611 - haiku/trunk/src/system/kernel/arch/x86/timers

  • From: stefano.ceccherini@xxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Wed, 24 Feb 2010 22:52:05 +0100 (CET)

Author: jackburton
Date: 2010-02-24 22:52:04 +0100 (Wed, 24 Feb 2010)
New Revision: 35611
Changeset: http://dev.haiku-os.org/changeset/35611/haiku

Modified:
   haiku/trunk/src/system/kernel/arch/x86/timers/x86_hpet.cpp
Log:
Fixed various problems which didn't let HPET timers work on my machine, most
notably:
- in hpet_clear_hardware_timer() we cleared the HPET_CONF_TIMER_INT_ENABLE
flag, and never set it back anymore (now we do, in hpet_set_hardware_timer())
- the incorrect interrupt configuration (although it shouldn't matter in legacy 
mode).
Also test the HPET counter before trying to use it.
Improved debug information.
HPET timers are still at priority 0, since I coulnd't yet test on other
machines (besides mine, QEMU and XenServer 5.5), and doen't work for
some reason with SMP enabled.


Modified: haiku/trunk/src/system/kernel/arch/x86/timers/x86_hpet.cpp
===================================================================
--- haiku/trunk/src/system/kernel/arch/x86/timers/x86_hpet.cpp  2010-02-24 
20:41:31 UTC (rev 35610)
+++ haiku/trunk/src/system/kernel/arch/x86/timers/x86_hpet.cpp  2010-02-24 
21:52:04 UTC (rev 35611)
@@ -3,6 +3,7 @@
  * Distributed under the terms of the MIT License.
  */
 
+#include <debug.h>
 #include <timer.h>
 #include <arch/x86/timer.h>
 #include <arch/x86/arch_hpet.h>
@@ -22,10 +23,13 @@
        #define TRACE(x) ;
 #endif
 
+#define TEST_HPET
+
 static struct hpet_regs *sHPETRegs;
 static volatile struct hpet_timer *sTimer;
+static uint64 sHPETPeriod;
 
-static int hpet_get_prio();
+static int hpet_get_priority();
 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);
@@ -33,7 +37,7 @@
 
 struct timer_info gHPETTimer = {
        "HPET",
-       &hpet_get_prio,
+       &hpet_get_priority,
        &hpet_set_hardware_timer,
        &hpet_clear_hardware_timer,
        &hpet_init
@@ -41,15 +45,16 @@
 
 
 static int
-hpet_get_prio()
+hpet_get_priority()
 {
-       return 0; //TODO: Should be 3, so it gets picked first
+       return 0; // TODO: Should have the highest priority
 }
 
 
 static int32
 hpet_timer_interrupt(void *arg)
 {
+       //dprintf_no_syslog("HPET timer_interrupt!!!!\n");
        return timer_interrupt();
 }
 
@@ -57,8 +62,8 @@
 static inline bigtime_t
 hpet_convert_timeout(const bigtime_t &relativeTimeout)
 {
-       return ((relativeTimeout * 1000000000LL)
-               / HPET_GET_PERIOD(sHPETRegs)) + sHPETRegs->u0.counter64;
+       return ((relativeTimeout * 1000000000ULL)
+               / sHPETPeriod) + sHPETRegs->u0.counter64;
 }
 
 
@@ -67,10 +72,15 @@
 {
        cpu_status state = disable_interrupts();
 
+       // enable timer interrupt
+       sTimer->config |= HPET_CONF_TIMER_INT_ENABLE;
+       
+       // TODO:
+       if (relativeTimeout < 3000)
+               relativeTimeout = 3000;
+               
        bigtime_t timerValue = hpet_convert_timeout(relativeTimeout);
        
-       //dprintf("setting value %lld, cur is %lld\n", timerValue, 
sHPETRegs->counter64);
-       
        sTimer->u0.comparator64 = timerValue;
 
        restore_interrupts(state);
@@ -82,7 +92,7 @@
 static status_t
 hpet_clear_hardware_timer()
 {
-       // Disable timer
+       // Disable timer interrupt
        sTimer->config &= ~HPET_CONF_TIMER_INT_ENABLE;
        return B_OK;
 }
@@ -120,20 +130,32 @@
 static void
 hpet_dump_timer(volatile struct hpet_timer *timer)
 {
-       dprintf(" routable interrupts:\n");
+       dprintf("HPET Timer %ld:\n", (timer - sHPETRegs->timer));
+               
+       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");
-       dprintf(" config: 0x%llx\n", timer->config);
-       dprintf(" configured interrupt: %lld\n",
+       dprintf("\tconfiguration: 0x%llx\n", timer->config);
+       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));
-       
-       dprintf(" fsb_route[0]: 0x%llx\n", timer->fsb_route[0]);
-       dprintf(" fsb_route[1]: 0x%llx\n", timer->fsb_route[1]);
+               
+       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
 
@@ -143,26 +165,43 @@
 {
        sTimer = timer;
        
-       // Configure timer for interrupt 0
-       sTimer->config &= (~HPET_CONF_TIMER_INT_ROUTE_MASK
-               << HPET_CONF_TIMER_INT_ROUTE_SHIFT);
+       uint32 interrupt = 0;
        
+       sTimer->config |= (interrupt << HPET_CONF_TIMER_INT_ROUTE_SHIFT)
+               & HPET_CONF_TIMER_INT_ROUTE_MASK;
+
        // Non-periodic mode, edge triggered
        sTimer->config &= ~(HPET_CONF_TIMER_TYPE | HPET_CONF_TIMER_INT_TYPE);
 
        sTimer->config &= ~HPET_CONF_TIMER_FSB_ENABLE;
+       sTimer->config &= ~HPET_CONF_TIMER_32MODE;
 
        // Enable timer
        sTimer->config |= HPET_CONF_TIMER_INT_ENABLE;
        
 #ifdef TRACE_HPET
-       dprintf("hpet_init_timer: timer %p, final configuration:\n", timer);
        hpet_dump_timer(sTimer);
 #endif
 }
 
 
 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(struct kernel_args *args)
 {
        /* hpet_acpi_probe() through a similar "scan spots" table
@@ -183,9 +222,12 @@
                }
        }
 
-       TRACE(("hpet_init: HPET is at %p. Vendor ID: %llx. Period: %lld\n",
-               sHPETRegs, HPET_GET_VENDOR_ID(sHPETRegs), 
HPET_GET_PERIOD(sHPETRegs)));
+       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;
@@ -206,23 +248,31 @@
                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++) {
-               TRACE(("hpet_init: timer %lu:\n", c));  
+       for (uint32 c = 0; c < numTimers; c++)
                hpet_dump_timer(&sHPETRegs->timer[c]);
-       }
 #endif
 
-       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_init_timer(&sHPETRegs->timer[0]);
+                       
+       status = hpet_set_enabled(true);
+       if (status != B_OK)
+               return status;
 
-       hpet_init_timer(&sHPETRegs->timer[2]);
+#ifdef TEST_HPET               
+       status = hpet_test();
+       if (status != B_OK)
+               return status;
+#endif
        
-       status = hpet_set_enabled(true);
-
+       int32 configuredIRQ = HPET_GET_CONF_TIMER_INT_ROUTE(sTimer);
+               
+       //install_io_interrupt_handler(0xfb - ARCH_INTERRUPT_BASE,
+               //&hpet_timer_interrupt, NULL, B_NO_LOCK_VECTOR);
+       install_io_interrupt_handler(configuredIRQ, &hpet_timer_interrupt,
+               NULL, B_NO_LOCK_VECTOR);
+       
        return status;
 }
 


Other related posts:

  • » [haiku-commits] r35611 - haiku/trunk/src/system/kernel/arch/x86/timers - stefano . ceccherini