ioapic_abi: More consistent function name w/ legacy interrupt
[dragonfly.git] / sys / platform / pc64 / isa / clock.c
index 716953a..13c5589 100644 (file)
@@ -70,6 +70,7 @@
 #include <sys/thread2.h>
 #include <sys/systimer.h>
 #include <sys/machintr.h>
+#include <sys/interrupt.h>
 
 #include <machine/clock.h>
 #ifdef CLK_CALIBRATION_LOOP
 #include <machine/segments.h>
 #include <machine/smp.h>
 #include <machine/specialreg.h>
+#include <machine/intr_machdep.h>
 
+#include <machine_base/apic/ioapic.h>
+#include <machine_base/apic/ioapic_abi.h>
 #include <machine_base/icu/icu.h>
 #include <bus/isa/isa.h>
 #include <bus/isa/rtc.h>
 #include <machine_base/isa/timerreg.h>
 
-#include <machine_base/isa/intr_machdep.h>
-
-#ifdef SMP /* APIC-IO */
-/* The interrupt triggered by the 8254 (timer) chip */
-int apic_8254_intr;
-static void setup_8254_mixed_mode (void);
-#endif
 static void i8254_restore(void);
 static void resettodr_on_shutdown(void *arg __unused);
 
@@ -115,7 +112,6 @@ static uint16_t i8254_walltimer_cntr;
 
 int    adjkerntz;              /* local offset from GMT in seconds */
 int    disable_rtc_set;        /* disable resettodr() if != 0 */
-int    statclock_disable = 1;  /* we don't use the statclock right now */
 int    tsc_present;
 int64_t        tsc_frequency;
 int    tsc_is_broken;
@@ -135,7 +131,7 @@ static  int rtc_loaded;
 static int i8254_cputimer_div;
 
 static int i8254_nointr;
-static int i8254_intr_disable = 0;
+static int i8254_intr_disable = 1;
 TUNABLE_INT("hw.i8254.intr_disable", &i8254_intr_disable);
 
 static struct callout sysbeepstop_ch;
@@ -213,7 +209,7 @@ clkintr(void *dummy, void *frame_arg)
                continue;
            if (gscan != gd) {
                lwkt_send_ipiq3(gscan, (ipifunc3_t)systimer_intr, 
-                               &sysclock_count, 0);
+                               &sysclock_count, 1);
            } else {
                systimer_intr(&sysclock_count, 0, frame_arg);
            }
@@ -254,35 +250,6 @@ release_timer2(void)
        return (0);
 }
 
-/*
- * This routine receives statistical clock interrupts from the RTC.
- * As explained above, these occur at 128 interrupts per second.
- * When profiling, we receive interrupts at a rate of 1024 Hz.
- *
- * This does not actually add as much overhead as it sounds, because
- * when the statistical clock is active, the hardclock driver no longer
- * needs to keep (inaccurate) statistics on its own.  This decouples
- * statistics gathering from scheduling interrupts.
- *
- * The RTC chip requires that we read status register C (RTC_INTR)
- * to acknowledge an interrupt, before it will generate the next one.
- * Under high interrupt load, rtcintr() can be indefinitely delayed and
- * the clock can tick immediately after the read from RTC_INTR.  In this
- * case, the mc146818A interrupt signal will not drop for long enough
- * to register with the 8259 PIC.  If an interrupt is missed, the stat
- * clock will halt, considerably degrading system performance.  This is
- * why we use 'while' rather than a more straightforward 'if' below.
- * Stat clock ticks can still be lost, causing minor loss of accuracy
- * in the statistics, but the stat clock will no longer stop.
- */
-static void
-rtcintr(void *dummy, void *frame)
-{
-       while (rtcin(RTC_INTR) & RTCIR_PERIOD)
-               ;
-               /* statclock(frame); no longer used */
-}
-
 #include "opt_ddb.h"
 #ifdef DDB
 #include <ddb/ddb.h>
@@ -519,6 +486,8 @@ sysbeep(int pitch, int period)
 {
        if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
                return(-1);
+       if (sysbeep_enable == 0)
+               return(-1);
        /*
         * Nobody else is using timer2, we do not need the clock lock
         */
@@ -1037,195 +1006,131 @@ resettodr(void)
        crit_exit();
 }
 
+static int
+i8254_ioapic_trial(int irq, struct cputimer_intr *cti)
+{
+       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(irq, mycpuid);
+
+       /*
+        * Force an 8254 Timer0 interrupt and wait 1/100s for
+        * it to happen, then see if we got it.
+        */
+       kprintf("IOAPIC: testing 8254 interrupt delivery\n");
+
+       i8254_intr_reload(cti, 2);
+       base = sys_cputimer->count();
+       while (sys_cputimer->count() - base < sys_cputimer->freq / 100)
+               ; /* nothing */
+
+       if (get_interrupt_counter(irq, mycpuid) - lastcnt == 0)
+               return ENOENT;
+       return 0;
+}
 
 /*
  * 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.
+ * interrupts.
  */
 static void
 i8254_intr_initclock(struct cputimer_intr *cti, boolean_t selected)
 {
-       int diag;
-#ifdef SMP /* APIC-IO */
-       int apic_8254_trial;
-       void *clkdesc;
-#endif
+       void *clkdesc = NULL;
+       int irq = 0, mixed_mode = 0, error;
 
-       callout_init(&sysbeepstop_ch);
+       KKASSERT(mycpuid == 0);
+       callout_init_mp(&sysbeepstop_ch);
 
-       if (!selected && i8254_intr_disable) {
-               i8254_nointr = 1; /* don't try to register again */
-               cputimer_intr_deregister(cti);
-               return;
-       }
+       if (!selected && i8254_intr_disable)
+               goto nointr;
 
-       if (statclock_disable) {
-               /*
-                * The stat interrupt mask is different without the
-                * statistics clock.  Also, don't set the interrupt
-                * flag which would normally cause the RTC to generate
-                * interrupts.
-                */
-               rtc_statusb = RTCSB_24HR;
-       } else {
-               /* Setting stathz to nonzero early helps avoid races. */
-               stathz = RTC_NOPROFRATE;
-               profhz = RTC_PROFRATE;
-        }
-
-       /* Finish initializing 8253 timer 0. */
-#ifdef SMP /* APIC-IO */
-if (apic_io_enable) {
-       apic_8254_intr = isa_apic_irq(0);
-       apic_8254_trial = 0;
-       if (apic_8254_intr >= 0 ) {
-               if (apic_int_type(0, 0) == 3)
-                       apic_8254_trial = 1;
+       /*
+        * The stat interrupt mask is different without the
+        * statistics clock.  Also, don't set the interrupt
+        * flag which would normally cause the RTC to generate
+        * interrupts.
+        */
+       rtc_statusb = RTCSB_24HR;
+
+       /* Finish initializing 8254 timer 0. */
+       if (ioapic_enable) {
+               irq = ioapic_find_legacy_by_irq(0, INTR_TRIGGER_EDGE,
+                       INTR_POLARITY_HIGH);
+               if (irq < 0) {
+mixed_mode_setup:
+                       error = ioapic_conf_legacy_extint(0);
+                       if (!error) {
+                               irq = ioapic_find_legacy_by_irq(0,
+                                   INTR_TRIGGER_EDGE, INTR_POLARITY_HIGH);
+                               if (irq < 0)
+                                       error = ENOENT;
+                       }
+
+                       if (error) {
+                               if (!selected) {
+                                       kprintf("IOAPIC: setup mixed mode for "
+                                               "irq 0 failed: %d\n", error);
+                                       goto nointr;
+                               } else {
+                                       panic("IOAPIC: setup mixed mode for "
+                                             "irq 0 failed: %d\n", error);
+                               }
+                       }
+                       mixed_mode = 1;
+               }
+               clkdesc = register_int(irq, clkintr, NULL, "clk",
+                                      NULL,
+                                      INTR_EXCL | INTR_CLOCK |
+                                      INTR_NOPOLL | INTR_MPSAFE |
+                                      INTR_NOENTROPY, 0);
        } else {
-               /* look for ExtInt on pin 0 */
-               if (apic_int_type(0, 0) == 3) {
-                       apic_8254_intr = apic_irq(0, 0);
-                       setup_8254_mixed_mode();
-               } else 
-                       panic("APIC_IO: Cannot route 8254 interrupt to CPU");
+               register_int(0, clkintr, NULL, "clk", NULL,
+                            INTR_EXCL | INTR_CLOCK |
+                            INTR_NOPOLL | INTR_MPSAFE |
+                            INTR_NOENTROPY, 0);
        }
 
-       clkdesc = register_int(apic_8254_intr, clkintr, NULL, "clk",
-                              NULL,
-                              INTR_EXCL | INTR_CLOCK |
-                              INTR_NOPOLL | INTR_MPSAFE | 
-                              INTR_NOENTROPY);
-       machintr_intren(apic_8254_intr);
-} else {
-#endif
-       register_int(0, clkintr, NULL, "clk", NULL,
-                    INTR_EXCL | INTR_CLOCK |
-                    INTR_NOPOLL | INTR_MPSAFE |
-                    INTR_NOENTROPY);
-       machintr_intren(ICU_IRQ0);
-#ifdef SMP /* APIC-IO */
-}
-#endif
-
        /* 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 SMP /* APIC-IO */
-if (apic_io_enable) {
-               if (isa_apic_irq(8) != 8)
-                       panic("APIC RTC != 8");
-}
-#endif
-
-               register_int(8, (inthand2_t *)rtcintr, NULL, "rtc", NULL,
-                            INTR_EXCL | INTR_CLOCK | INTR_NOPOLL |
-                            INTR_NOENTROPY);
-               machintr_intren(8);
-
-               writertc(RTC_STATUSB, rtc_statusb);
-       }
-
-#ifdef SMP /* APIC-IO */
-if (apic_io_enable) {
-       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);
-
-               /*
-                * 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");
-               i8254_intr_reload(cti, 2);
-               base = sys_cputimer->count();
-               while (sys_cputimer->count() - base < sys_cputimer->freq / 100)
-                       ;       /* nothing */
-               if (get_interrupt_counter(apic_8254_intr) - lastcnt == 0) {
-                       /* 
-                        * The MP table is broken.
-                        * The 8254 was not connected to the specified pin
-                        * on the IO APIC.
-                        * Workaround: Limited variant of mixed mode.
-                        */
-                       machintr_intrdis(apic_8254_intr);
-                       unregister_int(clkdesc);
-                       kprintf("APIC_IO: Broken MP table detected: "
-                              "8254 is not connected to "
-                              "IOAPIC #%d intpin %d\n",
-                              int_to_apicintpin[apic_8254_intr].ioapic,
-                              int_to_apicintpin[apic_8254_intr].int_pin);
-                       /* 
-                        * Revoke current ISA IRQ 0 assignment and 
-                        * configure a fallback interrupt routing from
-                        * the 8254 Timer via the 8259 PIC to the
-                        * an ExtInt interrupt line on IOAPIC #0 intpin 0.
-                        * We reuse the low level interrupt handler number.
-                        */
-                       if (apic_irq(0, 0) < 0) {
-                               revoke_apic_irq(apic_8254_intr);
-                               assign_apic_irq(0, 0, apic_8254_intr);
+       if (ioapic_enable) {
+               error = i8254_ioapic_trial(irq, cti);
+               if (error) {
+                       if (mixed_mode) {
+                               if (!selected) {
+                                       kprintf("IOAPIC: mixed mode for irq %d "
+                                               "trial failed: %d\n",
+                                               irq, error);
+                                       goto nointr;
+                               } else {
+                                       panic("IOAPIC: mixed mode for irq %d "
+                                             "trial failed: %d\n", irq, error);
+                               }
+                       } else {
+                               kprintf("IOAPIC: warning 8254 is not connected "
+                                       "to the correct pin, try mixed mode\n");
+                               unregister_int(clkdesc, 0);
+                               goto mixed_mode_setup;
                        }
-                       apic_8254_intr = apic_irq(0, 0);
-                       setup_8254_mixed_mode();
-                       register_int(apic_8254_intr, clkintr, NULL, "clk",
-                                    NULL,
-                                    INTR_EXCL | INTR_CLOCK |
-                                    INTR_NOPOLL | INTR_MPSAFE |
-                                    INTR_NOENTROPY);
-                       machintr_intren(apic_8254_intr);
                }
        }
-       if (apic_int_type(0, 0) != 3 ||
-           int_to_apicintpin[apic_8254_intr].ioapic != 0 ||
-           int_to_apicintpin[apic_8254_intr].int_pin != 0) {
-               kprintf("APIC_IO: routing 8254 via IOAPIC #%d intpin %d\n",
-                      int_to_apicintpin[apic_8254_intr].ioapic,
-                      int_to_apicintpin[apic_8254_intr].int_pin);
-       } else {
-               kprintf("APIC_IO: "
-                      "routing 8254 via 8259 and IOAPIC #0 intpin 0\n");
-       }
-}
-#endif
-}
-
-#ifdef SMP /* APIC-IO */
+       return;
 
-static void 
-setup_8254_mixed_mode(void)
-{
-       /*
-        * Allow 8254 timer to INTerrupt 8259:
-        *  re-initialize master 8259:
-        *   reset; prog 4 bytes, single ICU, edge triggered
-        */
-       outb(IO_ICU1, 0x13);
-       outb(IO_ICU1 + 1, IDT_OFFSET);  /* start vector (unused) */
-       outb(IO_ICU1 + 1, 0x00);        /* ignore slave */
-       outb(IO_ICU1 + 1, 0x03);        /* auto EOI, 8086 */
-       outb(IO_ICU1 + 1, 0xfe);        /* unmask INT0 */
-       
-       /* program IO APIC for type 3 INT on INT0 */
-       if (ext_int_setup(0, 0) < 0)
-               panic("8254 redirect via APIC pin0 impossible!");
+nointr:
+       i8254_nointr = 1; /* don't try to register again */
+       cputimer_intr_deregister(cti);
 }
-#endif
 
 void
 setstatclockrate(int newhz)