Date: Fri, 22 Jul 2011 08:16:52 -0400 From: John Baldwin <jhb@freebsd.org> To: freebsd-stable@freebsd.org Cc: Attilio Rao <attilio@freebsd.org>, Jung-uk Kim <jkim@freebsd.org>, Callum Gibson <callumgibson@optusnet.com.au>, freebsd-amd64@freebsd.org, Jeremy Chadwick <freebsd@jdc.parodius.com> Subject: Re: powernow regression in 8-STABLE Message-ID: <201107220816.52901.jhb@freebsd.org> In-Reply-To: <20110721214310.GA74656@icarus.home.lan> References: <20110719112033.GA51765@omma.gibson.athome> <20110721205600.GA52261@omma.gibson.athome> <20110721214310.GA74656@icarus.home.lan>
next in thread | previous in thread | raw e-mail | index | archive | help
On Thursday, July 21, 2011 5:43:10 pm Jeremy Chadwick wrote: > On Fri, Jul 22, 2011 at 06:56:00AM +1000, Callum Gibson wrote: > > On 21Jul11 12:07, Jung-uk Kim wrote: > > }Can you please do "set debug.cpufreq.verbose=1" from loader prompt and > > }show me the dmesg output? I want to see intial settings. You can > > }reset it from command line with "sysctl debug.cpufreq.verbose=0" > > }later. > > > > http://members.optusnet.com.au/callumgibson/boot_verboser.out > > > > Also, as suggested by jhb@, with legacy usb disabled: > > http://members.optusnet.com.au/callumgibson/boot_verboser_nousb.out > > and dev.cpu.0.freq reappears! Spooky. Is that a solution or a workaround? > > I noticed this disables usb keyboard support at the boot menus. > > "Legacy USB" support is a horribly-named BIOS option. > > What the option actually does, without getting into the technicalities, > is make your USB keyboard work inside of environments where there is no > USB driver. The most commonly-used examples are bootloader/bootstraps > and MS-DOS. > > The BIOS itself (meaning the firmware/BIOS, not "the BIOS as in a piece > of legacy technology") has a tiny USB stack in it. That's how your > USB keyboard is able to work (e.g. to press Del or F2 to get into the > BIOS itself), and how you're able to boot from USB-attached devices. > > You should keep "Legacy USB" enabled if you want your keyboard to work > in bootloaders/bootstraps. If enabling this feature breaks something > else, that sounds like a bug in the vendor BIOS to me, and you should > contact the vendor or motherboard manufacturer to inform them of the > bug. It's a known issue that the Legacy USB option can break our TSC calibration code causing an inflated value of the TSC frequency. The issue is that the legacy USB code is often very dumb. It is implemented via polling in SMI#. It appears that each interrupt from the ISA timer triggers an SMI# that polls the USB bus looking for any keyboards and checking for any pending keyboard events) that it can then use to trigger simulated PS/2 keyboard actions. The problem is that we calibrate the TSC using this algorithm: - grab the TSC - spin on the ISA timer waiting for it to run for a second - grab the TSC The issue is that the SMI# fires at the same time we want to be execuiting step 3, and step 3 is deferred while the SMI# handler runs. As a result, the TSC delta ends up being "1 second + time of an SMI# to poll USB". We have a hack fix for this at work that originally came from Attilio Rao. This is a patch for it relative to 8. It disables interrupt generation for the ISA timer while we calibrate the TSC (which disables the SMI# temporarily): Index: x86/isa/clock.c =================================================================== --- x86/isa/clock.c (.../mirror/FreeBSD/stable/8/sys) (revision 224114) +++ x86/isa/clock.c (.../stable/8/sys) (revision 224114) @@ -119,7 +119,7 @@ static unsigned i8254_get_timecount(struct timecounter *tc); static unsigned i8254_simple_get_timecount(struct timecounter *tc); -static void set_i8254_freq(u_int freq, int intr_freq); +static void set_i8254_freq(u_int freq, int intr_freq, int freerun); static struct timecounter i8254_timecounter = { i8254_get_timecount, /* get_timecount */ @@ -447,15 +447,32 @@ #endif } +/* + * XXX: This is a gross hack to workaround USB legacy emulation. For + * some systems, the USB legacy emulation is implemented by a periodic + * SMI# triggered by the i8254. The resulting SMI# could cause the + * DELAY() to run too long resulting in the TSC being miscalibrated. + * The workaround is to disable i8254 interrupts while calibrating the + * TSC. + */ +void +DELAY_TSCCAL(int n) +{ + + set_i8254_freq(i8254_freq, hz, 1); + DELAY(n); + set_i8254_freq(i8254_freq, hz, 0); +} + static void -set_i8254_freq(u_int freq, int intr_freq) +set_i8254_freq(u_int freq, int intr_freq, int freerun) { int new_i8254_real_max_count; i8254_timecounter.tc_frequency = freq; mtx_lock_spin(&clock_lock); i8254_freq = freq; - if (using_lapic_timer != LAPIC_CLOCK_NONE) + if (using_lapic_timer != LAPIC_CLOCK_NONE || freerun) new_i8254_real_max_count = 0x10000; else new_i8254_real_max_count = TIMER_DIV(intr_freq); @@ -508,7 +525,7 @@ { mtx_init(&clock_lock, "clk", NULL, MTX_SPIN | MTX_NOPROFILE); - set_i8254_freq(i8254_freq, hz); + set_i8254_freq(i8254_freq, hz, 0); } void @@ -517,7 +534,7 @@ atrtc_start(); - set_i8254_freq(i8254_freq, hz); + set_i8254_freq(i8254_freq, hz, 0); tc_init(&i8254_timecounter); init_TSC(); @@ -565,7 +582,7 @@ i8254_timecounter.tc_get_timecount = i8254_simple_get_timecount; i8254_timecounter.tc_counter_mask = 0xffff; - set_i8254_freq(i8254_freq, hz); + set_i8254_freq(i8254_freq, hz, 0); } /* @@ -627,7 +644,7 @@ freq = i8254_freq; error = sysctl_handle_int(oidp, &freq, 0, req); if (error == 0 && req->newptr != NULL) - set_i8254_freq(freq, hz); + set_i8254_freq(freq, hz, 0); return (error); } Index: amd64/include/clock.h =================================================================== --- amd64/include/clock.h (.../mirror/FreeBSD/stable/8/sys) (revision 224114) +++ amd64/include/clock.h (.../stable/8/sys) (revision 224114) @@ -32,10 +70,11 @@ /* * Driver to clock driver interface. */ void startrtclock(void); void init_TSC(void); void init_TSC_tc(void); +void DELAY_TSCCAL(int n); #define HAS_TIMER_SPKR 1 int timer_spkr_acquire(void); Index: amd64/amd64/tsc.c =================================================================== --- amd64/amd64/tsc.c (.../mirror/FreeBSD/stable/8/sys) (revision 224114) +++ amd64/amd64/tsc.c (.../stable/8/sys) (revision 224114) @@ -87,7 +92,7 @@ printf("Calibrating TSC clock ... "); tscval[0] = rdtsc(); - DELAY(1000000); + DELAY_TSCCAL(1000000); tscval[1] = rdtsc(); tsc_freq = tscval[1] - tscval[0]; -- John Baldwin
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201107220816.52901.jhb>