X-Git-Url: https://gitweb.dragonflybsd.org/~mneumann/dragonfly.git/blobdiff_plain/832eafe0c66b35d66bae59a86d7cc1da656b2d81..79b62055301f75e30e625e64f13564a1145fe853:/sys/platform/pc32/isa/clock.c diff --git a/sys/platform/pc32/isa/clock.c b/sys/platform/pc32/isa/clock.c index f02333dfb7..99ca676156 100644 --- a/sys/platform/pc32/isa/clock.c +++ b/sys/platform/pc32/isa/clock.c @@ -35,7 +35,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/pc32/isa/clock.c,v 1.55 2008/08/02 01:14:43 dillon Exp $ */ /* @@ -89,7 +88,7 @@ #include -#ifdef APIC_IO +#ifdef SMP /* APIC-IO */ /* The interrupt triggered by the 8254 (timer) chip */ int apic_8254_intr; static void setup_8254_mixed_mode (void); @@ -132,6 +131,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); @@ -152,6 +155,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 @@ -302,8 +324,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; @@ -311,8 +333,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; @@ -327,15 +349,15 @@ 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(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; @@ -420,6 +442,7 @@ DODELAY(int n, int doswitch) ticks_left -= delta; if (doswitch && ticks_left > 0) lwkt_switch(); + cpu_pause(); } #ifdef DELAYDEBUG if (state == 1) @@ -428,20 +451,25 @@ DODELAY(int n, int doswitch) #endif } +/* + * DELAY() never switches + */ void DELAY(int n) { DODELAY(n, 0); } +/* + * DRIVERSLEEP() does not switch if called with a spinlock held or + * from a hard interrupt. + */ void DRIVERSLEEP(int usec) { globaldata_t gd = mycpu; - if (gd->gd_intr_nesting_level || - gd->gd_spinlock_rd || - gd->gd_spinlocks_wr) { + if (gd->gd_intr_nesting_level || gd->gd_spinlocks_wr) { DODELAY(usec, 0); } else { DODELAY(usec, 1); @@ -612,6 +640,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. @@ -759,6 +792,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) @@ -841,7 +880,6 @@ void inittodr(time_t base) { unsigned long sec, days; - int yd; int year, month; int y, m; struct timespec ts; @@ -882,7 +920,6 @@ inittodr(time_t base) if ((month > 2) && LEAPYEAR(year)) days ++; days += readrtc(RTC_DAY) - 1; - yd = days; for (y = 1970; y < year; y++) days += DAYSPERYEAR + LEAPYEAR(y); sec = ((( days * 24 + @@ -976,14 +1013,22 @@ resettodr(void) * 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 +i8254_intr_initclock(struct cputimer_intr *cti, boolean_t selected) { int diag; -#ifdef APIC_IO +#ifdef SMP /* APIC-IO */ int apic_8254_trial; void *clkdesc; -#endif /* APIC_IO */ +#endif + + callout_init(&sysbeepstop_ch); + + if (!selected && i8254_intr_disable) { + i8254_nointr = 1; /* don't try to register again */ + cputimer_intr_deregister(cti); + return; + } if (statclock_disable) { /* @@ -1000,8 +1045,8 @@ cpu_initclocks(void *arg __unused) } /* Finish initializing 8253 timer 0. */ -#ifdef APIC_IO - +#ifdef SMP /* APIC-IO */ +if (apic_io_enable) { apic_8254_intr = isa_apic_irq(0); apic_8254_trial = 0; if (apic_8254_intr >= 0 ) { @@ -1018,20 +1063,20 @@ cpu_initclocks(void *arg __unused) clkdesc = register_int(apic_8254_intr, clkintr, NULL, "clk", NULL, - INTR_EXCL | INTR_FAST | + INTR_EXCL | INTR_CLOCK | INTR_NOPOLL | INTR_MPSAFE | INTR_NOENTROPY); machintr_intren(apic_8254_intr); - -#else /* APIC_IO */ - +} else { +#endif register_int(0, clkintr, NULL, "clk", NULL, - INTR_EXCL | INTR_FAST | + INTR_EXCL | INTR_CLOCK | INTR_NOPOLL | INTR_MPSAFE | INTR_NOENTROPY); machintr_intren(ICU_IRQ0); - -#endif /* APIC_IO */ +#ifdef SMP /* APIC-IO */ +} +#endif /* Initialize RTC. */ writertc(RTC_STATUSA, rtc_statusa); @@ -1042,33 +1087,42 @@ cpu_initclocks(void *arg __unused) if (diag != 0) kprintf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); -#ifdef APIC_IO +#ifdef SMP /* APIC-IO */ +if (apic_io_enable) { if (isa_apic_irq(8) != 8) panic("APIC RTC != 8"); -#endif /* APIC_IO */ +} +#endif register_int(8, (inthand2_t *)rtcintr, NULL, "rtc", NULL, - INTR_EXCL | INTR_FAST | INTR_NOPOLL | + INTR_EXCL | INTR_CLOCK | INTR_NOPOLL | INTR_NOENTROPY); machintr_intren(8); writertc(RTC_STATUSB, rtc_statusb); } -#ifdef APIC_IO +#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); /* - * 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 */ @@ -1101,12 +1155,11 @@ cpu_initclocks(void *arg __unused) setup_8254_mixed_mode(); register_int(apic_8254_intr, clkintr, NULL, "clk", NULL, - INTR_EXCL | INTR_FAST | + 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 || @@ -1118,12 +1171,11 @@ cpu_initclocks(void *arg __unused) kprintf("APIC_IO: " "routing 8254 via 8259 and IOAPIC #0 intpin 0\n"); } +} #endif - callout_init(&sysbeepstop_ch); } -SYSINIT(clocks8254, SI_BOOT2_CLOCKREG, SI_ORDER_FIRST, cpu_initclocks, NULL) -#ifdef APIC_IO +#ifdef SMP /* APIC-IO */ static void setup_8254_mixed_mode(void)