Duplicate platform/pc32/isa/clock.c to platform/pc64/isa/clock.c
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 17 May 2009 08:14:14 +0000 (16:14 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Sun, 17 May 2009 08:20:54 +0000 (16:20 +0800)
sys/platform/pc64/isa/clock.c

index ba5a449..8b6ca86 100644 (file)
@@ -36,7 +36,6 @@
  *
  *     from: @(#)clock.c       7.2 (Berkeley) 5/12/91
  * $FreeBSD: src/sys/i386/isa/clock.c,v 1.149.2.6 2002/11/02 04:41:50 iwasaki Exp $
- * $DragonFly: src/sys/platform/pc64/isa/clock.c,v 1.1 2008/08/29 17:07:19 dillon Exp $
  */
 
 /*
  * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94
  */
 
-//#include "use_apm.h"
-//#include "opt_clock.h"
+#if 0
+#include "use_apm.h"
+#include "opt_clock.h"
+#endif
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -125,10 +126,6 @@ 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;
@@ -137,6 +134,10 @@ static  int        rtc_loaded;
 
 static int i8254_cputimer_div;
 
+static int i8254_nointr;
+static int i8254_intr_disable = 0;
+TUNABLE_INT("hw.i8254.intr_disable", &i8254_intr_disable);
+
 static struct callout sysbeepstop_ch;
 
 static sysclock_t i8254_cputimer_count(void);
@@ -157,6 +158,25 @@ static struct cputimer     i8254_cputimer = {
     0, 0, 0
 };
 
+static void i8254_intr_reload(struct cputimer_intr *, sysclock_t);
+static void i8254_intr_config(struct cputimer_intr *, const struct cputimer *);
+static void i8254_intr_initclock(struct cputimer_intr *, boolean_t);
+
+static struct cputimer_intr i8254_cputimer_intr = {
+    .freq = TIMER_FREQ,
+    .reload = i8254_intr_reload,
+    .enable = cputimer_intr_default_enable,
+    .config = i8254_intr_config,
+    .restart = cputimer_intr_default_restart,
+    .pmfixup = cputimer_intr_default_pmfixup,
+    .initclock = i8254_intr_initclock,
+    .next = SLIST_ENTRY_INITIALIZER,
+    .name = "i8254",
+    .type = CPUTIMER_INTR_8254,
+    .prio = CPUTIMER_INTR_PRIO_8254,
+    .caps = CPUTIMER_INTR_CAP_PS
+};
+
 /*
  * timer0 clock interrupt.  Timer0 is in one-shot mode and has stopped
  * counting as of this interrupt.  We use timer1 in free-running mode (not
@@ -307,8 +327,8 @@ i8254_cputimer_count(void)
  * simple shift, multiplication, or division, we do so.  Otherwise 64
  * bit arithmatic is required every time the interrupt timer is reloaded.
  */
-void
-cputimer_intr_config(struct cputimer *timer)
+static void
+i8254_intr_config(struct cputimer_intr *cti, const struct cputimer *timer)
 {
     int freq;
     int div;
@@ -316,8 +336,8 @@ cputimer_intr_config(struct cputimer *timer)
     /*
      * Will a simple divide do the trick?
      */
-    div = (timer->freq + (i8254_cputimer.freq / 2)) / i8254_cputimer.freq;
-    freq = i8254_cputimer.freq * div;
+    div = (timer->freq + (cti->freq / 2)) / cti->freq;
+    freq = cti->freq * div;
 
     if (freq >= timer->freq - 1 && freq <= timer->freq + 1)
        i8254_cputimer_div = div;
@@ -333,14 +353,14 @@ cputimer_intr_config(struct cputimer *timer)
  * We may have to convert from the system timebase to the 8254 timebase.
  */
 static void
-i8254_intr_reload(sysclock_t reload)
+i8254_intr_reload(struct cputimer_intr *cti, sysclock_t reload)
 {
     __uint16_t count;
 
     if (i8254_cputimer_div)
        reload /= i8254_cputimer_div;
     else
-       reload = (int64_t)reload * i8254_cputimer.freq / sys_cputimer->freq;
+       reload = (int64_t)reload * cti->freq / sys_cputimer->freq;
 
     if ((int)reload < 2)
        reload = 2;
@@ -366,16 +386,6 @@ i8254_intr_reload(sysclock_t reload)
     clock_unlock();
 }
 
-void
-cputimer_intr_enable(void)
-{
-}
-
-void
-cputimer_intr_switch(enum cputimer_intr_type type)
-{
-}
-
 /*
  * DELAY(usec)      - Spin for the specified number of microseconds.
  * DRIVERSLEEP(usec) - Spin for the specified number of microseconds,
@@ -627,6 +637,11 @@ i8254_restore(void)
        outb(TIMER_CNTR0, 0);   /* msb */
        clock_unlock();
 
+       if (!i8254_nointr) {
+               cputimer_intr_register(&i8254_cputimer_intr);
+               cputimer_intr_select(&i8254_cputimer_intr, 0);
+       }
+
        /*
         * Timer1 or timer2 is our free-running clock, but only if another
         * has not been selected.
@@ -774,6 +789,12 @@ startrtclock(void)
 "CLK_USE_I8254_CALIBRATION not specified - using default frequency\n");
                freq = i8254_cputimer.freq;
 #endif
+               /*
+                * NOTE:
+                * Interrupt timer's freq must be adjusted
+                * before we change the cuptimer's frequency.
+                */
+               i8254_cputimer_intr.freq = freq;
                cputimer_set_frequency(&i8254_cputimer, freq);
        } else {
                if (bootverbose)
@@ -985,20 +1006,10 @@ resettodr(void)
        crit_exit();
 }
 
-
-/*
- * Start both clocks running.  DragonFly note: the stat clock is no longer
- * used.  Instead, 8254 based systimers are used for all major clock
- * interrupts.  statclock_disable is set by default.
- */
-void
-cpu_initclocks(void *arg __unused)
+static void
+cpu_initclocks(void)
 {
-       int diag;
-#ifdef APIC_IO
-       int apic_8254_trial;
-       void *clkdesc;
-#endif /* APIC_IO */
+       callout_init(&sysbeepstop_ch);
 
        if (statclock_disable) {
                /*
@@ -1009,14 +1020,60 @@ cpu_initclocks(void *arg __unused)
                 */
                rtc_statusb = RTCSB_24HR;
        } else {
-               /* Setting stathz to nonzero early helps avoid races. */
+               /* Setting stathz to nonzero early helps avoid races. */
                stathz = RTC_NOPROFRATE;
                profhz = RTC_PROFRATE;
-        }
+       }
 
-       /* Finish initializing 8253 timer 0. */
+       /* Initialize RTC. */
+       writertc(RTC_STATUSA, rtc_statusa);
+       writertc(RTC_STATUSB, RTCSB_24HR);
+
+       if (statclock_disable == 0) {
+               int diag;
+
+               diag = rtcin(RTC_DIAG);
+               if (diag != 0) {
+                       kprintf("RTC BIOS diagnostic error %b\n",
+                               diag, RTCDG_BITS);
+               }
+
+#ifdef APIC_IO
+               if (isa_apic_irq(8) != 8)
+                       panic("APIC RTC != 8");
+#endif /* APIC_IO */
+
+               register_int(8, (inthand2_t *)rtcintr, NULL, "rtc", NULL,
+                            INTR_EXCL | INTR_FAST | INTR_NOPOLL |
+                            INTR_NOENTROPY);
+               machintr_intren(8);
+
+               writertc(RTC_STATUSB, rtc_statusb);
+       }
+}
+SYSINIT(clockinit, SI_BOOT2_CLOCKREG, SI_ORDER_FIRST, cpu_initclocks, NULL)
+
+/*
+ * Start both clocks running.  DragonFly note: the stat clock is no longer
+ * used.  Instead, 8254 based systimers are used for all major clock
+ * interrupts.  statclock_disable is set by default.
+ */
+static void
+i8254_intr_initclock(struct cputimer_intr *cti, boolean_t selected)
+{
 #ifdef APIC_IO
+       int apic_8254_trial;
+       void *clkdesc;
+#endif /* APIC_IO */
 
+       if (!selected && i8254_intr_disable) {
+               i8254_nointr = 1; /* don't try to register again */
+               cputimer_intr_deregister(cti);
+               return;
+       }
+
+       /* Finish initializing 8253 timer 0. */
+#ifdef APIC_IO
        apic_8254_intr = isa_apic_irq(0);
        apic_8254_trial = 0;
        if (apic_8254_intr >= 0 ) {
@@ -1037,53 +1094,26 @@ cpu_initclocks(void *arg __unused)
                               INTR_NOPOLL | INTR_MPSAFE | 
                               INTR_NOENTROPY);
        machintr_intren(apic_8254_intr);
-       
-#else /* APIC_IO */
-
-       register_int(0, clkintr, NULL, "clk", NULL,
-                    INTR_EXCL | INTR_FAST | 
-                    INTR_NOPOLL | INTR_MPSAFE |
-                    INTR_NOENTROPY);
-       machintr_intren(ICU_IRQ0);
-
-#endif /* APIC_IO */
-
-       /* Initialize RTC. */
-       writertc(RTC_STATUSA, rtc_statusa);
-       writertc(RTC_STATUSB, RTCSB_24HR);
 
-       if (statclock_disable == 0) {
-               diag = rtcin(RTC_DIAG);
-               if (diag != 0)
-                       kprintf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS);
-
-#ifdef APIC_IO
-               if (isa_apic_irq(8) != 8)
-                       panic("APIC RTC != 8");
-#endif /* APIC_IO */
-
-               register_int(8, (inthand2_t *)rtcintr, NULL, "rtc", NULL,
-                            INTR_EXCL | INTR_FAST | INTR_NOPOLL |
-                            INTR_NOENTROPY);
-               machintr_intren(8);
-
-               writertc(RTC_STATUSB, rtc_statusb);
-       }
-
-#ifdef APIC_IO
        if (apic_8254_trial) {
                sysclock_t base;
                long lastcnt;
 
+               /*
+                * Following code assumes the 8254 is the cpu timer,
+                * so make sure it is.
+                */
+               KKASSERT(sys_cputimer == &i8254_cputimer);
+               KKASSERT(cti == &i8254_cputimer_intr);
+
                lastcnt = get_interrupt_counter(apic_8254_intr);
 
                /*
-                * XXX this assumes the 8254 is the cpu timer.  Force an
-                * 8254 Timer0 interrupt and wait 1/100s for it to happen,
-                * then see if we got it.
+                * Force an 8254 Timer0 interrupt and wait 1/100s for
+                * it to happen, then see if we got it.
                 */
                kprintf("APIC_IO: Testing 8254 interrupt delivery\n");
-               cputimer_intr_reload(2);        /* XXX assumes 8254 */
+               i8254_intr_reload(cti, 2);
                base = sys_cputimer->count();
                while (sys_cputimer->count() - base < sys_cputimer->freq / 100)
                        ;       /* nothing */
@@ -1121,7 +1151,6 @@ cpu_initclocks(void *arg __unused)
                                     INTR_NOENTROPY);
                        machintr_intren(apic_8254_intr);
                }
-               
        }
        if (apic_int_type(0, 0) != 3 ||
            int_to_apicintpin[apic_8254_intr].ioapic != 0 ||
@@ -1133,10 +1162,16 @@ cpu_initclocks(void *arg __unused)
                kprintf("APIC_IO: "
                       "routing 8254 via 8259 and IOAPIC #0 intpin 0\n");
        }
-#endif
-       callout_init(&sysbeepstop_ch);
+#else  /* !APIC_IO */
+
+       register_int(0, clkintr, NULL, "clk", NULL,
+                    INTR_EXCL | INTR_FAST | 
+                    INTR_NOPOLL | INTR_MPSAFE |
+                    INTR_NOENTROPY);
+       machintr_intren(ICU_IRQ0);
+
+#endif /* APIC_IO */
 }
-SYSINIT(clocks8254, SI_BOOT2_CLOCKREG, SI_ORDER_FIRST, cpu_initclocks, NULL)
 
 #ifdef APIC_IO