lapic timer: Finish the lapic timer support
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 2 May 2009 09:41:23 +0000 (17:41 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sat, 2 May 2009 13:53:48 +0000 (21:53 +0800)
- Add lapic_timer_process_oncpu(), which fires per-cpu systimer queue.
- Add lapic_timer_intr_reload(), which restart/start lapic timer.
- Change cputimer_intr_reload to function pointer, so it could be
  overridden when needed.  It is original cputimer_intr_reload function
  on amd64 and vkernel.  On i386, APIC initialization will set it to
  lapic_timer_intr_reload if lapic_timer_enable tunable is set to 1,
  else i8254_intr_reload (origial cputimer_intr_reload) will be used.
- If lapic_timer_enable is 1, then don't try to register "clk" interrupt
  handler at all.

As of this commit, lapic timer support is done.  It is not enabled by
default, set 'hw.lapci_timer_enable' to enable it.

sys/platform/pc32/apic/mpapic.c
sys/platform/pc32/isa/clock.c
sys/platform/pc64/isa/clock.c
sys/platform/vkernel/platform/systimer.c
sys/sys/systimer.h

index 773b14c..1fa6366 100644 (file)
 
 static void    lapic_timer_calibrate(void);
 static void    lapic_timer_set_divisor(int);
+static void    lapic_timer_intr_reload(sysclock_t);
+
 void           lapic_timer_process(void);
 void           lapic_timer_process_frame(struct intrframe *);
 void           lapic_timer_intr_test(void);
 void           lapic_timer_oneshot_intr_enable(void);
 
 int            lapic_timer_test;
+int            lapic_timer_enable;
+
 TUNABLE_INT("hw.lapic_timer_test", &lapic_timer_test);
+TUNABLE_INT("hw.lapic_timer_enable", &lapic_timer_enable);
 
 /*
  * pointers to pmapped apic hardware.
@@ -187,10 +192,13 @@ apic_initialize(boolean_t bsp)
                }
        }
 
-       if (bsp)
+       if (bsp) {
                lapic_timer_calibrate();
-       else
+               if (lapic_timer_enable)
+                       cputimer_intr_reload = lapic_timer_intr_reload;
+       } else {
                lapic_timer_set_divisor(lapic_timer_divisor_idx);
+       }
 
        if (bootverbose)
                apic_dump("apic_initialize()");
@@ -245,15 +253,29 @@ lapic_timer_calibrate(void)
                lapic_timer_divisor_idx, lapic_timer_freq);
 }
 
+static void
+lapic_timer_process_oncpu(struct globaldata *gd, struct intrframe *frame)
+{
+       sysclock_t count;
+
+       gd->gd_timer_running = 0;
+
+       count = sys_cputimer->count();
+       if (TAILQ_FIRST(&gd->gd_systimerq) != NULL)
+               systimer_intr(&count, 0, frame);
+}
+
 void
 lapic_timer_process(void)
 {
        struct globaldata *gd = mycpu;
 
-       gd->gd_timer_running = 0;
-
-       if (lapic_timer_test)
+       if (__predict_false(lapic_timer_test)) {
+               gd->gd_timer_running = 0;
                kprintf("%d proc\n", gd->gd_cpuid);
+       } else {
+               lapic_timer_process_oncpu(gd, NULL);
+       }
 }
 
 void
@@ -261,10 +283,12 @@ lapic_timer_process_frame(struct intrframe *frame)
 {
        struct globaldata *gd = mycpu;
 
-       gd->gd_timer_running = 0;
-
-       if (lapic_timer_test)
+       if (__predict_false(lapic_timer_test)) {
+               gd->gd_timer_running = 0;
                kprintf("%d proc frame\n", gd->gd_cpuid);
+       } else {
+               lapic_timer_process_oncpu(gd, frame);
+       }
 }
 
 void
@@ -279,6 +303,24 @@ lapic_timer_intr_test(void)
        }
 }
 
+static void
+lapic_timer_intr_reload(sysclock_t reload)
+{
+       struct globaldata *gd = mycpu;
+
+       reload = (int64_t)reload * lapic_timer_freq / sys_cputimer->freq;
+       if (reload < 2)
+               reload = 2;
+
+       if (gd->gd_timer_running) {
+               if (reload < lapic.ccr_timer)
+                       lapic_timer_oneshot_quick(reload);
+       } else {
+               gd->gd_timer_running = 1;
+               lapic_timer_oneshot_quick(reload);
+       }
+}
+
 void
 lapic_timer_oneshot_intr_enable(void)
 {
index 4c95906..ed6eb88 100644 (file)
@@ -124,6 +124,9 @@ enum tstate timer0_state;
 enum tstate timer1_state;
 enum tstate timer2_state;
 
+static void    i8254_intr_reload(sysclock_t);
+void           (*cputimer_intr_reload)(sysclock_t) = i8254_intr_reload;
+
 static int     beeping = 0;
 static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
 static u_char  rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
@@ -362,27 +365,32 @@ i8254_intr_reload(sysclock_t reload)
 }
 
 #ifdef SMP
+
 extern int     lapic_timer_test;
+extern int     lapic_timer_enable;
 extern void    lapic_timer_oneshot_intr_enable(void);
 extern void    lapic_timer_intr_test(void);
-#endif
 
-void
-cputimer_intr_reload(sysclock_t reload)
+/* Piggyback lapic_timer test */
+static void
+i8254_intr_reload_test(sysclock_t reload)
 {
        i8254_intr_reload(reload);
-#ifdef SMP
        if (__predict_false(lapic_timer_test))
                lapic_timer_intr_test();
-#endif
 }
 
+#endif /* SMP */
+
 void
 cputimer_intr_enable(void)
 {
 #ifdef SMP
-       if (lapic_timer_test)
+       if (lapic_timer_test || lapic_timer_enable) {
                lapic_timer_oneshot_intr_enable();
+               if (lapic_timer_test) /* XXX */
+                       cputimer_intr_reload = i8254_intr_reload_test;
+       }
 #endif
 }
 
@@ -1012,6 +1020,11 @@ cpu_initclocks(void *arg __unused)
 
        callout_init(&sysbeepstop_ch);
 
+#ifdef SMP
+       if (lapic_timer_enable)
+               return;
+#endif
+
        if (statclock_disable) {
                /*
                 * The stat interrupt mask is different without the
index 943da30..d5aefa4 100644 (file)
@@ -125,6 +125,10 @@ enum tstate timer0_state;
 enum tstate timer1_state;
 enum tstate timer2_state;
 
+
+static void    i8254_intr_reload(sysclock_t);
+void           (*cputimer_intr_reload)(sysclock_t) = i8254_intr_reload;
+
 static int     beeping = 0;
 static const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
 static u_char  rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
@@ -328,8 +332,8 @@ cputimer_intr_config(struct cputimer *timer)
  *
  * We may have to convert from the system timebase to the 8254 timebase.
  */
-void
-cputimer_intr_reload(sysclock_t reload)
+static void
+i8254_intr_reload(sysclock_t reload)
 {
     __uint16_t count;
 
index 6d282c5..b703ce5 100644 (file)
@@ -70,6 +70,9 @@ static struct kqueue_info *kqueue_timer_info;
 static int cputimer_mib[16];
 static int cputimer_miblen;
 
+static void    vkernel_intr_reload(sysclock_t);
+void           (*cputimer_intr_reload)(sysclock_t) = vkernel_intr_reload;
+
 
 /*
  * SYSTIMER IMPLEMENTATION
@@ -157,8 +160,8 @@ cputimer_intr_config(struct cputimer *timer)
  * reload calculation can be negatively indexed, we need a minimal
  * check to ensure that a reasonable reload value is selected. 
  */
-void
-cputimer_intr_reload(sysclock_t reload)
+static void
+vkernel_intr_reload(sysclock_t reload)
 {
        if (kqueue_timer_info) {
                if ((int)reload < 1)
index 45415f8..81668be 100644 (file)
@@ -138,7 +138,7 @@ void cputimer_default_destruct(struct cputimer *);
 
 void cputimer_intr_enable(void);
 void cputimer_intr_config(struct cputimer *);
-void cputimer_intr_reload(sysclock_t);
+extern void (*cputimer_intr_reload)(sysclock_t);
 
 #endif