Index: src/sys/amd64/amd64/io_apic.c =================================================================== RCS file: /home/ncvs/src/sys/amd64/amd64/io_apic.c,v retrieving revision 1.15.2.7 diff -u -r1.15.2.7 io_apic.c --- src/sys/amd64/amd64/io_apic.c 1 Dec 2006 17:13:56 -0000 1.15.2.7 +++ src/sys/amd64/amd64/io_apic.c 22 Dec 2006 04:42:08 -0000 @@ -431,6 +431,7 @@ volatile ioapic_t *apic; u_int numintr, i; uint32_t value; + int j; /* Map the register window so we can access the device. */ apic = (ioapic_t *)pmap_mapdev(addr, IOAPIC_MEM_REGION); @@ -478,6 +479,8 @@ * and level-triggered for all others. */ bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr); + if (getenv_int("hw.apic.idle_cpu", &j) == 0) + j = -1; mtx_lock_spin(&icu_lock); for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) { intpin->io_intsrc.is_pic = (struct pic *)io; @@ -489,7 +492,7 @@ * Assume that pins 1-15 are ISA interrupts and that all * other pins are PCI interrupts. */ - if (intpin->io_irq == 0) + if (intpin->io_irq == 0 && j != 2) ioapic_set_extint(io, i); else if (intpin->io_irq < IOAPIC_ISA_INTS) { intpin->io_bus = APIC_BUS_ISA; Index: src/sys/amd64/amd64/local_apic.c =================================================================== RCS file: /home/ncvs/src/sys/amd64/amd64/local_apic.c,v retrieving revision 1.17.2.11 diff -u -r1.17.2.11 local_apic.c --- src/sys/amd64/amd64/local_apic.c 29 Nov 2006 01:19:23 -0000 1.17.2.11 +++ src/sys/amd64/amd64/local_apic.c 22 Dec 2006 04:42:08 -0000 @@ -338,6 +338,7 @@ lapic_setup_clock(void) { u_long value; + int i; /* Can't drive the timer without a local APIC. */ if (lapic == NULL) @@ -379,7 +380,14 @@ */ lapic_timer_periodic(lapic_timer_period); lapic_timer_enable_intr(); - return (1); + + if (getenv_int("hw.apic.idle_cpu", &i) && i != 0) { + if (i != 2) + i = 1; + } else + i = 3; + + return ((lapic_timer_hz << 4) | i); } void Index: src/sys/amd64/isa/clock.c =================================================================== RCS file: /home/ncvs/src/sys/amd64/isa/clock.c,v retrieving revision 1.221.2.1 diff -u -r1.221.2.1 clock.c --- src/sys/amd64/isa/clock.c 18 Jul 2005 19:52:04 -0000 1.221.2.1 +++ src/sys/amd64/isa/clock.c 22 Dec 2006 04:42:09 -0000 @@ -115,6 +115,7 @@ static int (*i8254_pending)(struct intsrc *); static int i8254_ticked; static int using_lapic_timer; +static int rtc_reg = -1; static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; static u_char rtc_statusb = RTCSB_24HR; @@ -215,6 +216,8 @@ { while (rtcin(RTC_INTR) & RTCIR_PERIOD) { + if (using_lapic_timer) + continue; if (profprocs != 0) { if (--pscnt == 0) pscnt = psdiv; @@ -407,24 +410,30 @@ u_char val; RTC_LOCK; - outb(IO_RTC, reg); - inb(0x84); + if (rtc_reg != reg) { + inb(0x84); + outb(IO_RTC, reg); + rtc_reg = reg; + inb(0x84); + } val = inb(IO_RTC + 1); - inb(0x84); RTC_UNLOCK; return (val); } -static __inline void -writertc(u_char reg, u_char val) +static void +writertc(int reg, u_char val) { RTC_LOCK; - inb(0x84); - outb(IO_RTC, reg); - inb(0x84); + if (rtc_reg != reg) { + inb(0x84); + outb(IO_RTC, reg); + rtc_reg = reg; + inb(0x84); + } outb(IO_RTC + 1, val); - inb(0x84); /* XXX work around wrong order in rtcin() */ + inb(0x84); RTC_UNLOCK; } @@ -522,7 +531,7 @@ i8254_timecounter.tc_frequency = freq; mtx_lock_spin(&clock_lock); timer_freq = freq; - if (using_lapic_timer) + if (using_lapic_timer && using_lapic_timer != 2) new_timer0_real_max_count = 0x10000; else new_timer0_real_max_count = TIMER_DIV(intr_freq); @@ -730,27 +739,73 @@ void cpu_initclocks() { + u_int lapic_timer_hz; int diag; using_lapic_timer = lapic_setup_clock(); + if (using_lapic_timer) { + lapic_timer_hz = using_lapic_timer >> 4; + using_lapic_timer &= 0x0f; + } else + lapic_timer_hz = 0; /* * If we aren't using the local APIC timer to drive the kernel * clocks, setup the interrupt handler for the 8254 timer 0 so * that it can drive hardclock(). Otherwise, change the 8254 * timecounter to user a simpler algorithm. */ - if (!using_lapic_timer) { + if (!using_lapic_timer || using_lapic_timer == 2) { intr_add_handler("clk", 0, (driver_intr_t *)clkintr, NULL, INTR_TYPE_CLK | INTR_FAST, NULL); i8254_intsrc = intr_lookup_source(0); if (i8254_intsrc != NULL) i8254_pending = i8254_intsrc->is_pic->pic_source_pending; + else + panic("i8254: Timer not connected"); + if (using_lapic_timer) { + set_timer_freq(timer_freq, lapic_timer_hz); + if (bootverbose) + printf("i8254: Driving APIC timer at %u Hz\n", + lapic_timer_hz); + } } else { i8254_timecounter.tc_get_timecount = i8254_simple_get_timecount; i8254_timecounter.tc_counter_mask = 0xffff; set_timer_freq(timer_freq, hz); + if (using_lapic_timer == 1) { + if (lapic_timer_hz > 8192) + panic("RTC: Cannot drive %u Hz", + lapic_timer_hz); + + rtc_statusa = 0; + + if (lapic_timer_hz > 4096) + rtc_statusa |= RTCSA_8192; + else if (lapic_timer_hz > 2048) + rtc_statusa |= RTCSA_4096; + else if (lapic_timer_hz > 1024) + rtc_statusa |= RTCSA_2048; + else if (lapic_timer_hz > 512) + rtc_statusa |= RTCSA_1024; + else if (lapic_timer_hz > 256) + rtc_statusa |= RTCSA_512; + else if (lapic_timer_hz > 128) + rtc_statusa |= RTCSA_256; + else if (lapic_timer_hz > 64) + rtc_statusa |= RTCSA_128; + else if (lapic_timer_hz > 32) + rtc_statusa |= RTCSA_64; + else + rtc_statusa |= RTCSA_32; + + if (bootverbose) + printf("RTC: Driving APIC timer at %u Hz\n", + 1U << (16 - rtc_statusa)); + + rtc_statusa |= RTCSA_DIVIDER; + } } /* Initialize RTC. */ @@ -763,14 +818,19 @@ * kernel clocks, then setup the RTC to periodically interrupt to * drive statclock() and profclock(). */ - if (!statclock_disable && !using_lapic_timer) { + if ((!statclock_disable && !using_lapic_timer) || + using_lapic_timer == 1) { diag = rtcin(RTC_DIAG); if (diag != 0) printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); - /* Setting stathz to nonzero early helps avoid races. */ - stathz = RTC_NOPROFRATE; - profhz = RTC_PROFRATE; + if (!using_lapic_timer) { + /* + * Setting stathz to nonzero early helps avoid races. + */ + stathz = RTC_NOPROFRATE; + profhz = RTC_PROFRATE; + } /* Enable periodic interrupts from the RTC. */ rtc_statusb |= RTCSB_PINTR; Index: src/sys/i386/i386/io_apic.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/io_apic.c,v retrieving revision 1.20.2.7 diff -u -r1.20.2.7 io_apic.c --- src/sys/i386/i386/io_apic.c 1 Dec 2006 17:13:56 -0000 1.20.2.7 +++ src/sys/i386/i386/io_apic.c 22 Dec 2006 04:42:09 -0000 @@ -431,6 +431,7 @@ volatile ioapic_t *apic; u_int numintr, i; uint32_t value; + int j; /* Map the register window so we can access the device. */ apic = (ioapic_t *)pmap_mapdev(addr, IOAPIC_MEM_REGION); @@ -478,6 +479,8 @@ * and level-triggered for all others. */ bzero(io->io_pins, sizeof(struct ioapic_intsrc) * numintr); + if (getenv_int("hw.apic.idle_cpu", &j) == 0) + j = -1; mtx_lock_spin(&icu_lock); for (i = 0, intpin = io->io_pins; i < numintr; i++, intpin++) { intpin->io_intsrc.is_pic = (struct pic *)io; @@ -489,7 +492,7 @@ * Assume that pins 1-15 are ISA interrupts and that all * other pins are PCI interrupts. */ - if (intpin->io_irq == 0) + if (intpin->io_irq == 0 && j != 2) ioapic_set_extint(io, i); else if (intpin->io_irq < IOAPIC_ISA_INTS) { intpin->io_bus = APIC_BUS_ISA; Index: src/sys/i386/i386/local_apic.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/local_apic.c,v retrieving revision 1.17.2.11 diff -u -r1.17.2.11 local_apic.c --- src/sys/i386/i386/local_apic.c 29 Nov 2006 01:19:22 -0000 1.17.2.11 +++ src/sys/i386/i386/local_apic.c 22 Dec 2006 04:42:09 -0000 @@ -339,6 +339,7 @@ lapic_setup_clock(void) { u_long value; + int i; /* Can't drive the timer without a local APIC. */ if (lapic == NULL) @@ -380,7 +381,14 @@ */ lapic_timer_periodic(lapic_timer_period); lapic_timer_enable_intr(); - return (1); + + if (getenv_int("hw.apic.idle_cpu", &i) && i != 0) { + if (i != 2) + i = 1; + } else + i = 3; + + return ((lapic_timer_hz << 4) | i); } void Index: src/sys/i386/isa/clock.c =================================================================== RCS file: /home/ncvs/src/sys/i386/isa/clock.c,v retrieving revision 1.222.2.2 diff -u -r1.222.2.2 clock.c --- src/sys/i386/isa/clock.c 22 Aug 2006 16:52:42 -0000 1.222.2.2 +++ src/sys/i386/isa/clock.c 22 Dec 2006 04:42:09 -0000 @@ -129,6 +129,7 @@ static int (*i8254_pending)(struct intsrc *); static int i8254_ticked; static int using_lapic_timer; +static int rtc_reg = -1; static u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF; static u_char rtc_statusb = RTCSB_24HR; @@ -234,6 +235,8 @@ { while (rtcin(RTC_INTR) & RTCIR_PERIOD) { + if (using_lapic_timer) + continue; if (profprocs != 0) { if (--pscnt == 0) pscnt = psdiv; @@ -426,24 +429,30 @@ u_char val; RTC_LOCK; - outb(IO_RTC, reg); - inb(0x84); + if (rtc_reg != reg) { + inb(0x84); + outb(IO_RTC, reg); + rtc_reg = reg; + inb(0x84); + } val = inb(IO_RTC + 1); - inb(0x84); RTC_UNLOCK; return (val); } -static __inline void -writertc(u_char reg, u_char val) +static void +writertc(int reg, u_char val) { RTC_LOCK; - inb(0x84); - outb(IO_RTC, reg); - inb(0x84); + if (rtc_reg != reg) { + inb(0x84); + outb(IO_RTC, reg); + rtc_reg = reg; + inb(0x84); + } outb(IO_RTC + 1, val); - inb(0x84); /* XXX work around wrong order in rtcin() */ + inb(0x84); RTC_UNLOCK; } @@ -546,7 +555,7 @@ i8254_timecounter.tc_frequency = freq; mtx_lock_spin(&clock_lock); timer_freq = freq; - if (using_lapic_timer) + if (using_lapic_timer && using_lapic_timer != 2) new_timer0_real_max_count = 0x10000; else new_timer0_real_max_count = TIMER_DIV(intr_freq); @@ -792,10 +801,19 @@ void cpu_initclocks() { + u_int lapic_timer_hz; int diag; #ifdef DEV_APIC using_lapic_timer = lapic_setup_clock(); + if (using_lapic_timer) { + lapic_timer_hz = using_lapic_timer >> 4; + using_lapic_timer &= 0x0f; + } else + lapic_timer_hz = 0; +#else + using_lapic_timer = 0; + lapic_timer_hz = 0; #endif /* * If we aren't using the local APIC timer to drive the kernel @@ -803,18 +821,58 @@ * that it can drive hardclock(). Otherwise, change the 8254 * timecounter to user a simpler algorithm. */ - if (!using_lapic_timer) { + if (!using_lapic_timer || using_lapic_timer == 2) { intr_add_handler("clk", 0, (driver_intr_t *)clkintr, NULL, INTR_TYPE_CLK | INTR_FAST, NULL); i8254_intsrc = intr_lookup_source(0); if (i8254_intsrc != NULL) i8254_pending = i8254_intsrc->is_pic->pic_source_pending; + else + panic("i8254: Timer not connected"); + if (using_lapic_timer) { + set_timer_freq(timer_freq, lapic_timer_hz); + if (bootverbose) + printf("i8254: Driving APIC timer at %u Hz\n", + lapic_timer_hz); + } } else { i8254_timecounter.tc_get_timecount = i8254_simple_get_timecount; i8254_timecounter.tc_counter_mask = 0xffff; set_timer_freq(timer_freq, hz); + if (using_lapic_timer == 1) { + if (lapic_timer_hz > 8192) + panic("RTC: Cannot drive %u Hz", + lapic_timer_hz); + + rtc_statusa = 0; + + if (lapic_timer_hz > 4096) + rtc_statusa |= RTCSA_8192; + else if (lapic_timer_hz > 2048) + rtc_statusa |= RTCSA_4096; + else if (lapic_timer_hz > 1024) + rtc_statusa |= RTCSA_2048; + else if (lapic_timer_hz > 512) + rtc_statusa |= RTCSA_1024; + else if (lapic_timer_hz > 256) + rtc_statusa |= RTCSA_512; + else if (lapic_timer_hz > 128) + rtc_statusa |= RTCSA_256; + else if (lapic_timer_hz > 64) + rtc_statusa |= RTCSA_128; + else if (lapic_timer_hz > 32) + rtc_statusa |= RTCSA_64; + else + rtc_statusa |= RTCSA_32; + + if (bootverbose) + printf("RTC: Driving APIC timer at %u Hz\n", + 1U << (16 - rtc_statusa)); + + rtc_statusa |= RTCSA_DIVIDER; + } } /* Initialize RTC. */ @@ -827,14 +885,19 @@ * kernel clocks, then setup the RTC to periodically interrupt to * drive statclock() and profclock(). */ - if (!statclock_disable && !using_lapic_timer) { + if ((!statclock_disable && !using_lapic_timer) || + using_lapic_timer == 1) { diag = rtcin(RTC_DIAG); if (diag != 0) printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS); - /* Setting stathz to nonzero early helps avoid races. */ - stathz = RTC_NOPROFRATE; - profhz = RTC_PROFRATE; + if (!using_lapic_timer) { + /* + * Setting stathz to nonzero early helps avoid races. + */ + stathz = RTC_NOPROFRATE; + profhz = RTC_PROFRATE; + } /* Enable periodic interrupts from the RTC. */ rtc_statusb |= RTCSB_PINTR;