--- include/clock.h@@/main/sandvine_plt_neutron/0 2007-10-05 14:32:29.000000000 -0400 +++ include/clock.h@@/main/sandvine_plt_neutron/1 2007-10-09 11:14:15.000000000 -0400 @@ -38,6 +38,7 @@ int sysbeep(int pitch, int period); void timer_restore(void); void init_TSC(void); void init_TSC_tc(void); +void DELAY_TSCCAL(int n); #endif /* _KERNEL */ --- isa/clock.c@@/main/RELENG_6/sandvine_bsd_6_main/sandvine_plt_neutron/1 2007-03-09 17:24:23.000000000 -0500 +++ isa/clock.c@@/main/RELENG_6/sandvine_bsd_6_main/sandvine_plt_neutron/2 2007-10-09 11:15:01.000000000 -0400 @@ -142,7 +142,7 @@ static u_char timer2_state; static unsigned i8254_get_timecount(struct timecounter *tc); static unsigned i8254_simple_get_timecount(struct timecounter *tc); -static void set_timer_freq(u_int freq, int intr_freq); +static void set_timer_freq(u_int freq, int intr_freq, int freerun); static struct timecounter i8254_timecounter = { i8254_get_timecount, /* get_timecount */ @@ -308,7 +308,7 @@ DELAY(int n) * early for console i/o. */ if (timer0_max_count == 0) - set_timer_freq(timer_freq, hz); + set_timer_freq(timer_freq, hz, 0); /* * Read the counter first, so that the rest of the setup overhead is @@ -388,6 +388,20 @@ DELAY(int n) #endif } +/* + * XXX This is a gross hack for reqst00084792. The tsc clock frequency was + * being miscalibrated by about 0.1%, due to some issue with a new BIOS version + * from SuperMicro. To avoid the issue we let the i8254 counter free run so + * that we're virtually guaranteed not to miss a counter rollover. + */ +void +DELAY_TSCCAL(int n) +{ + set_timer_freq(timer_freq, hz, 1); + DELAY(n); + set_timer_freq(timer_freq, hz, 0); +} + static void sysbeepstop(void *chan) { @@ -535,18 +549,19 @@ fail: if (bootverbose) printf("failed, using default i8254 clock of %u Hz\n", timer_freq); + return (timer_freq); } static void -set_timer_freq(u_int freq, int intr_freq) +set_timer_freq(u_int freq, int intr_freq, int freerun) { int new_timer0_real_max_count; i8254_timecounter.tc_frequency = freq; mtx_lock_spin(&clock_lock); timer_freq = freq; - if (using_lapic_timer) + if (using_lapic_timer || freerun) new_timer0_real_max_count = 0x10000; else new_timer0_real_max_count = TIMER_DIV(intr_freq); @@ -613,7 +628,7 @@ startrtclock() writertc(RTC_STATUSA, rtc_statusa); writertc(RTC_STATUSB, RTCSB_24HR); - set_timer_freq(timer_freq, hz); + set_timer_freq(timer_freq, hz, 0); freq = calibrate_clocks(); #ifdef CLK_CALIBRATION_LOOP if (bootverbose) { @@ -645,7 +660,7 @@ startrtclock() freq, timer_freq); } - set_timer_freq(timer_freq, hz); + set_timer_freq(timer_freq, hz, 0); tc_init(&i8254_timecounter); init_TSC(); @@ -815,7 +830,7 @@ cpu_initclocks() i8254_timecounter.tc_get_timecount = i8254_simple_get_timecount; i8254_timecounter.tc_counter_mask = 0xffff; - set_timer_freq(timer_freq, hz); + set_timer_freq(timer_freq, hz, 0); } /* Initialize RTC. */ @@ -884,7 +899,7 @@ sysctl_machdep_i8254_freq(SYSCTL_HANDLER freq = timer_freq; error = sysctl_handle_int(oidp, &freq, sizeof(freq), req); if (error == 0 && req->newptr != NULL) - set_timer_freq(freq, hz); + set_timer_freq(freq, hz, 0); return (error); } --- i386/tsc.c@@/main/sandvine_plt_neutron/0 2007-09-21 10:29:02.000000000 -0400 +++ i386/tsc.c@@/main/sandvine_plt_neutron/1 2007-10-09 11:15:30.000000000 -0400 @@ -80,7 +80,7 @@ init_TSC(void) printf("Calibrating TSC clock ... "); tscval[0] = rdtsc(); - DELAY(1000000); + DELAY_TSCCAL(1000000); tscval[1] = rdtsc(); tsc_freq = tscval[1] - tscval[0];