diff --git a/sys/amd64/amd64/local_apic.c b/sys/amd64/amd64/local_apic.c index 98ed4df8307d..0d04bbd4a696 100644 --- a/sys/amd64/amd64/local_apic.c +++ b/sys/amd64/amd64/local_apic.c @@ -160,6 +160,9 @@ static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value); struct pic lapic_pic = { .pic_resume = lapic_resume }; +static int lapic_allclocks; +TUNABLE_INT("machdep.lapic_allclocks", &lapic_allclocks); + static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value) { @@ -415,10 +418,11 @@ lapic_disable_pmc(void) /* * Called by cpu_initclocks() on the BSP to setup the local APIC timer so * that it can drive hardclock, statclock, and profclock. This function - * returns true if it is able to use the local APIC timer to drive the - * clocks and false if it is not able. + * returns a positive integer if it is convenient to use the local APIC + * for all the clocks, a negative integer if it is convenient to use the + * local APIC only for the hardclock and 0 if none of them can be handled. */ -int +enum lapic_clock lapic_setup_clock(void) { u_long value; @@ -426,10 +430,10 @@ lapic_setup_clock(void) /* Can't drive the timer without a local APIC. */ if (lapic == NULL) - return (0); + return (LAPIC_CLOCK_NONE); if (resource_int_value("apic", 0, "clock", &i) == 0 && i == 0) - return (0); + return (LAPIC_CLOCK_NONE); /* Start off with a divisor of 2 (power on reset default). */ lapic_timer_divisor = 2; @@ -461,19 +465,27 @@ lapic_setup_clock(void) * (and profhz) run at hz. If 'hz' is below 1500 but above * 750, then we let the lapic timer run at 2 * 'hz'. If 'hz' * is below 750 then we let the lapic timer run at 4 * 'hz'. + * + * Please note that stathz and profhz are set only if all the + * clocks are handled through the local APIC. */ - if (hz >= 1500) + if (lapic_allclocks != 0) { + if (hz >= 1500) + lapic_timer_hz = hz; + else if (hz >= 750) + lapic_timer_hz = hz * 2; + else + lapic_timer_hz = hz * 4; + } else lapic_timer_hz = hz; - else if (hz >= 750) - lapic_timer_hz = hz * 2; - else - lapic_timer_hz = hz * 4; - if (lapic_timer_hz < 128) - stathz = lapic_timer_hz; - else - stathz = lapic_timer_hz / (lapic_timer_hz / 128); - profhz = lapic_timer_hz; lapic_timer_period = value / lapic_timer_hz; + if (lapic_allclocks != 0) { + if (lapic_timer_hz < 128) + stathz = lapic_timer_hz; + else + stathz = lapic_timer_hz / (lapic_timer_hz / 128); + profhz = lapic_timer_hz; + } /* * Start up the timer on the BSP. The APs will kick off their @@ -481,7 +493,7 @@ lapic_setup_clock(void) */ lapic_timer_periodic(lapic_timer_period); lapic_timer_enable_intr(); - return (1); + return (lapic_allclocks == 0 ? LAPIC_CLOCK_HARDCLOCK : LAPIC_CLOCK_ALL); } void @@ -784,20 +796,23 @@ lapic_handle_timer(struct trapframe *frame) else hardclock_cpu(TRAPF_USERMODE(frame)); } + if (lapic_allclocks != 0) { - /* Fire statclock at stathz. */ - la->la_stat_ticks += stathz; - if (la->la_stat_ticks >= lapic_timer_hz) { - la->la_stat_ticks -= lapic_timer_hz; - statclock(TRAPF_USERMODE(frame)); - } + /* Fire statclock at stathz. */ + la->la_stat_ticks += stathz; + if (la->la_stat_ticks >= lapic_timer_hz) { + la->la_stat_ticks -= lapic_timer_hz; + statclock(TRAPF_USERMODE(frame)); + } - /* Fire profclock at profhz, but only when needed. */ - la->la_prof_ticks += profhz; - if (la->la_prof_ticks >= lapic_timer_hz) { - la->la_prof_ticks -= lapic_timer_hz; - if (profprocs != 0) - profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); + /* Fire profclock at profhz, but only when needed. */ + la->la_prof_ticks += profhz; + if (la->la_prof_ticks >= lapic_timer_hz) { + la->la_prof_ticks -= lapic_timer_hz; + if (profprocs != 0) + profclock(TRAPF_USERMODE(frame), + TRAPF_PC(frame)); + } } critical_exit(); } diff --git a/sys/amd64/include/apicvar.h b/sys/amd64/include/apicvar.h index 9d6d538de1d8..8f15d84a1ac3 100644 --- a/sys/amd64/include/apicvar.h +++ b/sys/amd64/include/apicvar.h @@ -157,6 +157,12 @@ #define APIC_BUS_PCI 2 #define APIC_BUS_MAX APIC_BUS_PCI +enum lapic_clock { + LAPIC_CLOCK_NONE, + LAPIC_CLOCK_HARDCLOCK, + LAPIC_CLOCK_ALL +}; + /* * An APIC enumerator is a psuedo bus driver that enumerates APIC's including * CPU's and I/O APIC's. @@ -224,7 +230,7 @@ int lapic_set_lvt_triggermode(u_int apic_id, u_int lvt, enum intr_trigger trigger); void lapic_set_tpr(u_int vector); void lapic_setup(int boot); -int lapic_setup_clock(void); +enum lapic_clock lapic_setup_clock(void); #endif /* !LOCORE */ #endif /* _MACHINE_APICVAR_H_ */ diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c index adc174358955..bf379f3287e5 100644 --- a/sys/amd64/isa/clock.c +++ b/sys/amd64/isa/clock.c @@ -91,7 +91,7 @@ static u_int32_t i8254_offset; static int (*i8254_pending)(struct intsrc *); static int i8254_ticked; static int using_atrtc_timer; -static int using_lapic_timer; +static enum lapic_clock using_lapic_timer = LAPIC_CLOCK_NONE; /* Values for timerX_state: */ #define RELEASED 0 @@ -160,7 +160,8 @@ clkintr(struct trapframe *frame) clkintr_pending = 0; mtx_unlock_spin(&clock_lock); } - KASSERT(!using_lapic_timer, ("clk interrupt enabled with lapic timer")); + KASSERT(using_lapic_timer == LAPIC_CLOCK_NONE, + ("clk interrupt enabled with lapic timer")); if (using_atrtc_timer) { #ifdef SMP @@ -422,7 +423,7 @@ set_i8254_freq(u_int freq, int intr_freq) i8254_timecounter.tc_frequency = freq; mtx_lock_spin(&clock_lock); i8254_freq = freq; - if (using_lapic_timer) + if (using_lapic_timer != LAPIC_CLOCK_NONE) new_i8254_real_max_count = 0x10000; else new_i8254_real_max_count = TIMER_DIV(intr_freq); @@ -485,7 +486,7 @@ cpu_initclocks() * that it can drive hardclock(). Otherwise, change the 8254 * timecounter to user a simpler algorithm. */ - if (!using_lapic_timer) { + if (using_lapic_timer == LAPIC_CLOCK_NONE) { intr_add_handler("clk", 0, (driver_filter_t *)clkintr, NULL, NULL, INTR_TYPE_CLK, NULL); i8254_intsrc = intr_lookup_source(0); @@ -508,7 +509,7 @@ cpu_initclocks() * kernel clocks, then setup the RTC to periodically interrupt to * drive statclock() and profclock(). */ - if (!using_lapic_timer) { + if (using_lapic_timer != LAPIC_CLOCK_ALL) { using_atrtc_timer = atrtc_setup_clock(); if (using_atrtc_timer) { /* Enable periodic interrupts from the RTC. */ @@ -532,7 +533,7 @@ void cpu_startprofclock(void) { - if (using_lapic_timer || !using_atrtc_timer) + if (using_lapic_timer == LAPIC_CLOCK_ALL || !using_atrtc_timer) return; atrtc_rate(RTCSA_PROF); psdiv = pscnt = psratio; @@ -542,7 +543,7 @@ void cpu_stopprofclock(void) { - if (using_lapic_timer || !using_atrtc_timer) + if (using_lapic_timer == LAPIC_CLOCK_ALL || !using_atrtc_timer) return; atrtc_rate(RTCSA_NOPROF); psdiv = pscnt = 1; diff --git a/sys/conf/files.pc98 b/sys/conf/files.pc98 index 002cf86d39a4..b4e171dfdc19 100644 --- a/sys/conf/files.pc98 +++ b/sys/conf/files.pc98 @@ -194,7 +194,7 @@ i386/ibcs2/ibcs2_util.c optional ibcs2 i386/ibcs2/ibcs2_xenix.c optional ibcs2 i386/ibcs2/ibcs2_xenix_sysent.c optional ibcs2 i386/ibcs2/imgact_coff.c optional ibcs2 -i386/isa/atpic.c standard +i386/isa/atpic.c optional atpic #i386/isa/atpic_vector.s standard i386/isa/elink.c optional ep | ie i386/isa/isa.c optional isa @@ -240,7 +240,7 @@ pc98/cbus/gdc.c optional gdc pc98/cbus/nmi.c standard pc98/cbus/olpt.c optional olpt pc98/cbus/pckbd.c optional pckbd -pc98/cbus/pcrtc.c standard +pc98/cbus/pcrtc.c optional atpic pc98/cbus/pmc.c optional pmc pc98/cbus/scgdcrndr.c optional sc gdc pc98/cbus/scterm-sck.c optional sc diff --git a/sys/conf/options.i386 b/sys/conf/options.i386 index a8e40e1462d3..333ec6a8dfbf 100644 --- a/sys/conf/options.i386 +++ b/sys/conf/options.i386 @@ -106,6 +106,7 @@ NETGRAPH_CRONYX opt_ng_cronyx.h # Device options DEV_APIC opt_apic.h +DEV_ATPIC opt_atpic.h DEV_NPX opt_npx.h ASR_COMPAT opt_asr.h diff --git a/sys/conf/options.pc98 b/sys/conf/options.pc98 index dca3d694ae74..a10737be7672 100644 --- a/sys/conf/options.pc98 +++ b/sys/conf/options.pc98 @@ -90,6 +90,7 @@ PC98 opt_global.h # Device options DEV_APIC opt_apic.h +DEV_ATPIC opt_atpic.h DEV_MECIA opt_mecia.h DEV_NPX opt_npx.h diff --git a/sys/i386/i386/local_apic.c b/sys/i386/i386/local_apic.c index 1451ec808e30..e0049c8cf5b3 100644 --- a/sys/i386/i386/local_apic.c +++ b/sys/i386/i386/local_apic.c @@ -34,6 +34,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_atpic.h" #include "opt_hwpmc_hooks.h" #include "opt_kdtrace.h" @@ -160,6 +161,17 @@ static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value); struct pic lapic_pic = { .pic_resume = lapic_resume }; +/* + * The atrtc device is compiled in only if atpic is present. + * If it is not, force lapic to take care of all the clocks. + */ +#ifdef DEV_ATPIC +static int lapic_allclocks; +TUNABLE_INT("machdep.lapic_allclocks", &lapic_allclocks); +#else +static int lapic_allclocks = 1; +#endif + static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value) { @@ -416,11 +428,9 @@ lapic_disable_pmc(void) /* * Called by cpu_initclocks() on the BSP to setup the local APIC timer so - * that it can drive hardclock, statclock, and profclock. This function - * returns true if it is able to use the local APIC timer to drive the - * clocks and false if it is not able. + * that it can drive hardclock, statclock, and profclock. */ -int +enum lapic_clock lapic_setup_clock(void) { u_long value; @@ -428,10 +438,10 @@ lapic_setup_clock(void) /* Can't drive the timer without a local APIC. */ if (lapic == NULL) - return (0); + return (LAPIC_CLOCK_NONE); if (resource_int_value("apic", 0, "clock", &i) == 0 && i == 0) - return (0); + return (LAPIC_CLOCK_NONE); /* Start off with a divisor of 2 (power on reset default). */ lapic_timer_divisor = 2; @@ -463,19 +473,27 @@ lapic_setup_clock(void) * (and profhz) run at hz. If 'hz' is below 1500 but above * 750, then we let the lapic timer run at 2 * 'hz'. If 'hz' * is below 750 then we let the lapic timer run at 4 * 'hz'. + * + * Please note that stathz and profhz are set only if all the + * clocks are handled through the local APIC. */ - if (hz >= 1500) + if (lapic_allclocks != 0) { + if (hz >= 1500) + lapic_timer_hz = hz; + else if (hz >= 750) + lapic_timer_hz = hz * 2; + else + lapic_timer_hz = hz * 4; + } else lapic_timer_hz = hz; - else if (hz >= 750) - lapic_timer_hz = hz * 2; - else - lapic_timer_hz = hz * 4; - if (lapic_timer_hz < 128) - stathz = lapic_timer_hz; - else - stathz = lapic_timer_hz / (lapic_timer_hz / 128); - profhz = lapic_timer_hz; lapic_timer_period = value / lapic_timer_hz; + if (lapic_allclocks != 0) { + if (lapic_timer_hz < 128) + stathz = lapic_timer_hz; + else + stathz = lapic_timer_hz / (lapic_timer_hz / 128); + profhz = lapic_timer_hz; + } /* * Start up the timer on the BSP. The APs will kick off their @@ -483,7 +501,7 @@ lapic_setup_clock(void) */ lapic_timer_periodic(lapic_timer_period); lapic_timer_enable_intr(); - return (1); + return (lapic_allclocks == 0 ? LAPIC_CLOCK_HARDCLOCK : LAPIC_CLOCK_ALL); } void @@ -786,20 +804,23 @@ lapic_handle_timer(struct trapframe *frame) else hardclock_cpu(TRAPF_USERMODE(frame)); } + if (lapic_allclocks != 0) { - /* Fire statclock at stathz. */ - la->la_stat_ticks += stathz; - if (la->la_stat_ticks >= lapic_timer_hz) { - la->la_stat_ticks -= lapic_timer_hz; - statclock(TRAPF_USERMODE(frame)); - } + /* Fire statclock at stathz. */ + la->la_stat_ticks += stathz; + if (la->la_stat_ticks >= lapic_timer_hz) { + la->la_stat_ticks -= lapic_timer_hz; + statclock(TRAPF_USERMODE(frame)); + } - /* Fire profclock at profhz, but only when needed. */ - la->la_prof_ticks += profhz; - if (la->la_prof_ticks >= lapic_timer_hz) { - la->la_prof_ticks -= lapic_timer_hz; - if (profprocs != 0) - profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); + /* Fire profclock at profhz, but only when needed. */ + la->la_prof_ticks += profhz; + if (la->la_prof_ticks >= lapic_timer_hz) { + la->la_prof_ticks -= lapic_timer_hz; + if (profprocs != 0) + profclock(TRAPF_USERMODE(frame), + TRAPF_PC(frame)); + } } critical_exit(); } diff --git a/sys/i386/include/apicvar.h b/sys/i386/include/apicvar.h index b15452b1d81c..2f8e716089d5 100644 --- a/sys/i386/include/apicvar.h +++ b/sys/i386/include/apicvar.h @@ -186,6 +186,12 @@ #define APIC_BUS_PCI 2 #define APIC_BUS_MAX APIC_BUS_PCI +enum lapic_clock { + LAPIC_CLOCK_NONE, + LAPIC_CLOCK_HARDCLOCK, + LAPIC_CLOCK_ALL +}; + /* * An APIC enumerator is a psuedo bus driver that enumerates APIC's including * CPU's and I/O APIC's. @@ -253,7 +259,7 @@ int lapic_set_lvt_triggermode(u_int apic_id, u_int lvt, enum intr_trigger trigger); void lapic_set_tpr(u_int vector); void lapic_setup(int boot); -int lapic_setup_clock(void); +enum lapic_clock lapic_setup_clock(void); #endif /* !LOCORE */ #endif /* _MACHINE_APICVAR_H_ */ diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c index 12e76e4b7ea9..e999b5619ddf 100644 --- a/sys/i386/isa/clock.c +++ b/sys/i386/isa/clock.c @@ -65,9 +65,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef DEV_APIC #include -#endif #include #include #include @@ -106,7 +104,7 @@ static u_int32_t i8254_offset; static int (*i8254_pending)(struct intsrc *); static int i8254_ticked; static int using_atrtc_timer; -static int using_lapic_timer; +static enum lapic_clock using_lapic_timer = LAPIC_CLOCK_NONE; /* Values for timerX_state: */ #define RELEASED 0 @@ -175,7 +173,8 @@ clkintr(struct trapframe *frame) clkintr_pending = 0; mtx_unlock_spin(&clock_lock); } - KASSERT(!using_lapic_timer, ("clk interrupt enabled with lapic timer")); + KASSERT(using_lapic_timer == LAPIC_CLOCK_NONE, + ("clk interrupt enabled with lapic timer")); #ifdef KDTRACE_HOOKS /* @@ -453,7 +452,7 @@ set_i8254_freq(u_int freq, int intr_freq) i8254_timecounter.tc_frequency = freq; mtx_lock_spin(&clock_lock); i8254_freq = freq; - if (using_lapic_timer) + if (using_lapic_timer != LAPIC_CLOCK_NONE) new_i8254_real_max_count = 0x10000; else new_i8254_real_max_count = TIMER_DIV(intr_freq); @@ -533,7 +532,7 @@ cpu_initclocks() * that it can drive hardclock(). Otherwise, change the 8254 * timecounter to user a simpler algorithm. */ - if (!using_lapic_timer) { + if (using_lapic_timer == LAPIC_CLOCK_NONE) { intr_add_handler("clk", 0, (driver_filter_t *)clkintr, NULL, NULL, INTR_TYPE_CLK, NULL); i8254_intsrc = intr_lookup_source(0); @@ -556,7 +555,7 @@ cpu_initclocks() * kernel clocks, then setup the RTC to periodically interrupt to * drive statclock() and profclock(). */ - if (!using_lapic_timer) { + if (using_lapic_timer != LAPIC_CLOCK_ALL) { using_atrtc_timer = atrtc_setup_clock(); if (using_atrtc_timer) { /* Enable periodic interrupts from the RTC. */ @@ -580,7 +579,7 @@ void cpu_startprofclock(void) { - if (using_lapic_timer || !using_atrtc_timer) + if (using_lapic_timer == LAPIC_CLOCK_ALL || !using_atrtc_timer) return; atrtc_rate(RTCSA_PROF); psdiv = pscnt = psratio; @@ -590,7 +589,7 @@ void cpu_stopprofclock(void) { - if (using_lapic_timer || !using_atrtc_timer) + if (using_lapic_timer == LAPIC_CLOCK_ALL || !using_atrtc_timer) return; atrtc_rate(RTCSA_NOPROF); psdiv = pscnt = 1; diff --git a/sys/i386/xen/exception.s b/sys/i386/xen/exception.s index 607f96a46b2f..e965ffd026d3 100644 --- a/sys/i386/xen/exception.s +++ b/sys/i386/xen/exception.s @@ -295,10 +295,6 @@ ENTRY(fork_trampoline) SUPERALIGN_TEXT MCOUNT_LABEL(bintr) -#ifdef DEV_ATPIC -#include -#endif - #ifdef DEV_APIC .data .p2align 4 diff --git a/sys/pc98/cbus/clock.c b/sys/pc98/cbus/clock.c index bb651bdc3a64..10b259868135 100644 --- a/sys/pc98/cbus/clock.c +++ b/sys/pc98/cbus/clock.c @@ -67,9 +67,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#ifdef DEV_APIC #include -#endif #include #include #include @@ -101,7 +99,7 @@ static u_int32_t i8254_lastcount; static u_int32_t i8254_offset; static int (*i8254_pending)(struct intsrc *); static int i8254_ticked; -static int using_lapic_timer; +static enum lapic_clock using_lapic_timer = LAPIC_CLOCK_NONE; /* Values for timerX_state: */ #define RELEASED 0 @@ -164,7 +162,8 @@ clkintr(struct trapframe *frame) clkintr_pending = 0; mtx_unlock_spin(&clock_lock); } - KASSERT(!using_lapic_timer, ("clk interrupt enabled with lapic timer")); + KASSERT(using_lapic_timer == LAPIC_CLOCK_NONE, + ("clk interrupt enabled with lapic timer")); #ifdef KDTRACE_HOOKS /* @@ -360,7 +359,7 @@ set_i8254_freq(u_int freq, int intr_freq) i8254_timecounter.tc_frequency = freq; mtx_lock_spin(&clock_lock); i8254_freq = freq; - if (using_lapic_timer) + if (using_lapic_timer != LAPIC_CLOCK_NONE) new_i8254_real_max_count = 0x10000; else new_i8254_real_max_count = TIMER_DIV(intr_freq); @@ -443,7 +442,7 @@ cpu_initclocks() * that it can drive hardclock(). Otherwise, change the 8254 * timecounter to user a simpler algorithm. */ - if (!using_lapic_timer) { + if (using_lapic_timer == LAPIC_CLOCK_NONE) { intr_add_handler("clk", 0, (driver_filter_t *)clkintr, NULL, NULL, INTR_TYPE_CLK, NULL); i8254_intsrc = intr_lookup_source(0); diff --git a/sys/pc98/conf/DEFAULTS b/sys/pc98/conf/DEFAULTS index 0002cf0a30cc..f30501e44ac1 100644 --- a/sys/pc98/conf/DEFAULTS +++ b/sys/pc98/conf/DEFAULTS @@ -24,3 +24,6 @@ device uart_ns8250 # Default partitioning schemes options GEOM_PART_BSD options GEOM_PART_PC98 + +# enable support for native hardware +device atpic