Re: [PATCH RFC] x86, tsc: Allow for high latency in quick_pit_calibrate()

From: George Spelvin
Date: Fri Jun 05 2015 - 01:53:14 EST


FWIW, I wrote my own test routine, with some interesting results.
It's a rude bodge and obviously not kernel-quality, but included if
anyone wants to mess with it.

My machine is an X79 motherboard with a common ITE IT8728F SuperIO
chip providing both RTC and PIT.

The intersting bit is that I can double the speed of the PIT code, and
the really interesting part is that the RTC code is 18% faster still
(85% of the time).

It's running at 3.4 GHz, so I expect 729478 ticks per 256 PIT
counts, and 415039 ticks per 8192 Hz RTC tick.


Anyway, here are the results using the current pit_expect_msb().
The values printed are the returned tsc, the delta to the previous one,
and the uncertainty range, which is the time for two reads
94 inb() operations).


PIT edge at 99066193034, delta 0, range 18372
PIT edge at 99066918775, delta 725741, range 18372
PIT edge at 99067644199, delta 725424, range 18372
PIT edge at 99068379191, delta 734992, range 18372
PIT edge at 99069104615, delta 725424, range 18372
PIT edge at 99069839127, delta 734512, range 18372
PIT edge at 99070564551, delta 725424, range 18372
PIT edge at 99071299583, delta 735032, range 18348
PIT edge at 99072025530, delta 725947, range 18372
PIT edge at 99072750839, delta 725309, range 18372
PIT edge at 99073485447, delta 734608, range 18372
PIT edge at 99074210778, delta 725331, range 18372
PIT edge at 99074945471, delta 734693, range 18372
PIT edge at 99075670807, delta 725336, range 18372
PIT edge at 99076406543, delta 735736, range 18372
PIT edge at 99077132874, delta 726331, range 18372
PIT edge at 99077858095, delta 725221, range 18372
PIT edge at 99078593719, delta 735624, range 18372
PIT edge at 99079319255, delta 725536, range 18372
PIT edge at 99080053767, delta 734512, range 18372
PIT edge at 99080779079, delta 725312, range 18372
PIT edge at 99081504322, delta 725243, range 18372
PIT edge at 99082239311, delta 734989, range 18372
PIT edge at 99082964554, delta 725243, range 18372
PIT edge at 99083699543, delta 734989, range 18372
PIT edge at 99084425602, delta 726059, range 18372
PIT edge at 99085160095, delta 734493, range 18372
PIT edge at 99085885311, delta 725216, range 18372
PIT edge at 99086610535, delta 725224, range 18372
PIT edge at 99087345751, delta 735216, range 18372
PIT edge at 99088071399, delta 725648, range 18372
PIT edge at 99088805911, delta 734512, range 18372
PIT edge at 99089531519, delta 725608, range 18372
PIT edge at 99090266327, delta 734808, range 18372
PIT edge at 99090991567, delta 725240, range 18372
PIT edge at 99091716767, delta 725200, range 18372
PIT edge at 99092451279, delta 734512, range 18372
PIT edge at 99093176615, delta 725336, range 18487
PIT edge at 99093911423, delta 734808, range 18372
PIT edge at 99094636847, delta 725424, range 18372
PIT edge at 99095371447, delta 734600, range 18372
PIT edge at 99096096671, delta 725224, range 18372
PIT edge at 99096831703, delta 735032, range 18372
PIT edge at 99097557535, delta 725832, range 18372
PIT edge at 99098282959, delta 725424, range 18372
PIT edge at 99099018063, delta 735104, range 18372
PIT edge at 99099743303, delta 725240, range 18372
PIT edge at 99100477703, delta 734400, range 18372
PIT edge at 99101203015, delta 725312, range 18372
PIT edge at 99101937415, delta 734400, range 18372

Here's the same for an optimized PIT routine, which places the PIT in
msbyte-only mode, so only needs one read to poll the PIT.

It also prints the number of iterations inside the PIT spin loop.

Note that it's exactly twice the speed, but the variance
is much higher.

PIT edge at 99131203367, delta 0, range 9215, iter 158
PIT edge at 99131929383, delta 726016, range 9172, iter 157
PIT edge at 99132659519, delta 730136, range 9215, iter 158
PIT edge at 99133389546, delta 730027, range 9172, iter 158
PIT edge at 99134120047, delta 730501, range 9188, iter 158
PIT edge at 99134850095, delta 730048, range 9508, iter 158
PIT edge at 99135580303, delta 730208, range 9188, iter 158
PIT edge at 99136310623, delta 730320, range 9188, iter 158
PIT edge at 99137035935, delta 725312, range 9193, iter 157
PIT edge at 99137765754, delta 729819, range 9172, iter 158
PIT edge at 99138495666, delta 729912, range 9172, iter 158
PIT edge at 99139225578, delta 729912, range 9172, iter 158
PIT edge at 99139955511, delta 729933, range 9172, iter 158
PIT edge at 99140685311, delta 729800, range 9212, iter 158
PIT edge at 99141415743, delta 730432, range 9215, iter 158
PIT edge at 99142146247, delta 730504, range 9169, iter 158
PIT edge at 99142872303, delta 726056, range 9215, iter 157
PIT edge at 99143603031, delta 730728, range 9215, iter 158
PIT edge at 99144333559, delta 730528, range 9169, iter 158
PIT edge at 99145063879, delta 730320, range 9193, iter 158
PIT edge at 99145793791, delta 729912, range 9193, iter 158
PIT edge at 99146519823, delta 726032, range 9191, iter 157
PIT edge at 99147249735, delta 729912, range 9191, iter 158
PIT edge at 99147979559, delta 729824, range 9212, iter 158
PIT edge at 99148709674, delta 730115, range 9172, iter 158
PIT edge at 99149440311, delta 730637, range 9212, iter 158
PIT edge at 99150170743, delta 730432, range 9172, iter 158
PIT edge at 99150896055, delta 725312, range 9212, iter 157
PIT edge at 99151626487, delta 730432, range 9215, iter 158
PIT edge at 99152357103, delta 730616, range 9212, iter 158
PIT edge at 99153087242, delta 730139, range 9172, iter 158
PIT edge at 99153817154, delta 729912, range 9172, iter 158
PIT edge at 99154547271, delta 730117, range 9188, iter 158
PIT edge at 99155272671, delta 725400, range 9188, iter 157
PIT edge at 99156003103, delta 730432, range 9191, iter 158
PIT edge at 99156733423, delta 730320, range 9191, iter 158
PIT edge at 99157464063, delta 730640, range 9188, iter 158
PIT edge at 99158194087, delta 730024, range 9191, iter 158
PIT edge at 99158924498, delta 730411, range 9172, iter 158
PIT edge at 99159650239, delta 725741, range 9191, iter 157
PIT edge at 99160380039, delta 729800, range 9212, iter 158
PIT edge at 99161110583, delta 730544, range 9172, iter 158
PIT edge at 99161840495, delta 729912, range 9215, iter 158
PIT edge at 99162570815, delta 730320, range 9215, iter 158
PIT edge at 99163300911, delta 730096, range 9169, iter 158
PIT edge at 99164030823, delta 729912, range 9169, iter 158
PIT edge at 99164756767, delta 725944, range 9188, iter 157
PIT edge at 99165486703, delta 729936, range 9188, iter 158
PIT edge at 99166216818, delta 730115, range 9196, iter 158
PIT edge at 99166946730, delta 729912, range 9196, iter 158

Now here's the RTC version. Because the events being times are
faster, the delta is expected to be 415039. But what's interesting
is that the read time is singificantly lower and (with the
exception of one outlier) more stable.

Is the simpler metastability handling (we're only reading
one bit, rather than an entire counter) causing the difference?

(PIT reads are 1353 ns each, while RTC reads are 1142 ns.)

RTC edge at 99172986783, delta 0, range 7764, iter 7
RTC edge at 99173401719, delta 414936, range 7764, iter 106
RTC edge at 99173816543, delta 414824, range 7764, iter 106
RTC edge at 99174231391, delta 414848, range 7764, iter 106
RTC edge at 99174646119, delta 414728, range 7740, iter 106
RTC edge at 99175061351, delta 415232, range 7764, iter 106
RTC edge at 99175476399, delta 415048, range 7764, iter 106
RTC edge at 99175891223, delta 414824, range 7764, iter 106
RTC edge at 99176306071, delta 414848, range 7764, iter 106
RTC edge at 99176721415, delta 415344, range 7764, iter 106
RTC edge at 99177136551, delta 415136, range 7764, iter 106
RTC edge at 99177552010, delta 415459, range 7764, iter 106
RTC edge at 99177966831, delta 414821, range 7764, iter 106
RTC edge at 99178381567, delta 414736, range 7764, iter 106
RTC edge at 99178797226, delta 415659, range 7764, iter 106
RTC edge at 99179211959, delta 414733, range 7764, iter 106
RTC edge at 99179627007, delta 415048, range 7764, iter 106
RTC edge at 99180041943, delta 414936, range 7764, iter 106
RTC edge at 99180457378, delta 415435, range 7764, iter 106
RTC edge at 99180872335, delta 414957, range 7764, iter 106
RTC edge at 99181287271, delta 414936, range 7764, iter 106
RTC edge at 99181702095, delta 414824, range 7764, iter 106
RTC edge at 99182120815, delta 418720, range 7764, iter 107
RTC edge at 99182535935, delta 415120, range 7764, iter 106
RTC edge at 99182951095, delta 415160, range 7764, iter 106
RTC edge at 99183366215, delta 415120, range 7764, iter 106
RTC edge at 99183781082, delta 414867, range 7764, iter 106
RTC edge at 99184192639, delta 411557, range 7764, iter 105
RTC edge at 99184611431, delta 418792, range 7764, iter 107
RTC edge at 99185026391, delta 414960, range 7764, iter 106
RTC edge at 99185441527, delta 415136, range 7764, iter 106
RTC edge at 99185853135, delta 411608, range 8172, iter 105
RTC edge at 99186268658, delta 415523, range 7764, iter 106
RTC edge at 99186683687, delta 415029, range 7764, iter 106
RTC edge at 99187098415, delta 414728, range 7764, iter 106
RTC edge at 99187513351, delta 414936, range 7764, iter 106
RTC edge at 99187928287, delta 414936, range 7764, iter 106
RTC edge at 99188346895, delta 418608, range 7764, iter 107
RTC edge at 99188761946, delta 415051, range 7764, iter 106
RTC edge at 99189176679, delta 414733, range 7764, iter 106
RTC edge at 99189591818, delta 415139, range 7764, iter 106
RTC edge at 99190006959, delta 415141, range 7764, iter 106
RTC edge at 99190422303, delta 415344, range 7764, iter 106
RTC edge at 99190837463, delta 415160, range 7764, iter 106
RTC edge at 99191249135, delta 411672, range 7764, iter 105
RTC edge at 99191664071, delta 414936, range 7764, iter 106
RTC edge at 99192082679, delta 418608, range 7764, iter 107
RTC edge at 99192494127, delta 411448, range 7764, iter 105
RTC edge at 99192912735, delta 418608, range 7764, iter 107
RTC edge at 99193327602, delta 414867, range 7764, iter 106
tsc: Fast TSC calibration using PIT
Using user defined TSC freq: 3399.965 MHz
tsc: Detected 3399.965 MHz processor
Calibrating delay loop (skipped), value calculated using timer frequency.. 6802.26 BogoMIPS (lpj=11333216)


Here's my ugly code. The "skanky stuff" is a race condition that will
break if an NMI comes along, but I'm not sure that['s possible this
early in the boot.


diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c
index a00f35be..7399d4c6 100644
--- a/arch/x86/kernel/tsc.c
+++ b/arch/x86/kernel/tsc.c
@@ -22,6 +22,8 @@
#include <asm/nmi.h>
#include <asm/x86_init.h>

+#include <asm/mc146818rtc.h>
+
unsigned int __read_mostly cpu_khz; /* TSC clocks / usec, not used here */
EXPORT_SYMBOL(cpu_khz);

@@ -533,15 +535,15 @@ static inline int pit_verify_msb(unsigned char val)

static inline int pit_expect_msb(unsigned char val, u64 *tscp, unsigned long *deltap)
{
- int count;
- u64 tsc = 0, prev_tsc = 0;
+ int count = 0;
+ u64 prev_tsc, tsc = 0;

- for (count = 0; count < 50000; count++) {
- if (!pit_verify_msb(val))
- break;
+ do {
+ if (++count > 50000)
+ return 0;
prev_tsc = tsc;
tsc = get_cycles();
- }
+ } while (pit_verify_msb(val));
*deltap = get_cycles() - prev_tsc;
*tscp = tsc;

@@ -552,6 +554,158 @@ static inline int pit_expect_msb(unsigned char val, u64 *tscp, unsigned long *de
return count > 5;
}

+/* Similar, but only a single read. And returns the number of reads. */
+static inline unsigned
+pit_expect_msb1(unsigned char val, u64 *tscp, unsigned long *deltap)
+{
+ int count = 0;
+ u64 prev_tsc, tsc = 0;
+
+ do {
+ if (++count > 50000)
+ return 0;
+ prev_tsc = tsc;
+ tsc = get_cycles();
+ } while (inb(0x42) == val);
+ *deltap = get_cycles() - prev_tsc;
+ *tscp = tsc;
+
+ return count;
+}
+
+static inline unsigned
+rtc_wait_bit(u64 *tscp, unsigned long *deltap)
+{
+ int count = 0;
+ u64 prev_tsc, tsc = 0;
+
+ do {
+ if (++count > 5000)
+ return 0;
+ prev_tsc = tsc;
+ tsc = get_cycles();
+ } while (~inb(RTC_PORT(1)) & RTC_PF); /* Wait for bit 6 to be set */
+ *deltap = get_cycles() - prev_tsc;
+ *tscp = tsc;
+
+ /*
+ * We require _some_ success, but the quality control
+ * will be based on the error terms on the TSC values.
+ */
+ return count;
+}
+
+#define SAMPLES 50
+static void noinline_for_stack
+pit_test(void)
+{
+ u64 tsc[SAMPLES];
+ unsigned long delta[SAMPLES];
+ unsigned count[SAMPLES];
+ int i;
+ unsigned char saved_a, saved_b;
+ unsigned long flags;
+ extern spinlock_t rtc_lock;
+
+ outb(0xb0, 0x43);
+
+ /* Start at 0xffff */
+ outb(0xff, 0x42);
+ outb(0xff, 0x42);
+
+ pit_verify_msb(0);
+
+ if (pit_expect_msb(0xff, tsc+0, delta+0)) {
+ int j;
+ u64 prev;
+ for (i = 1; i < SAMPLES; i++) {
+ if (!pit_expect_msb(0xff-i, tsc+i, delta+i))
+ break;
+ if (!pit_verify_msb(0xfe - i))
+ break;
+ }
+ prev = tsc[0];
+ for (j = 0; j < i; j++) {
+ printk("PIT edge at %12llu, delta %7llu, range %6lu\n",
+ tsc[j], tsc[j] - prev, delta[j]);
+ prev = tsc[j];
+ }
+ }
+
+ /* Try again, with one-byte reads */
+ outb(0xa0, 0x43);
+ outb(0xff, 0x42); /* Start at 0xff00 */
+
+ /* Wait until we reach 0xfe (should be very fast) */
+ pit_verify_msb(0);
+ for (i = 0; i < 1000; i++)
+ if (inb(0x42) == 0xfe)
+ break;
+
+ if (i < 1000) {
+ int j;
+ u64 prev;
+
+ for (i = 0; i < SAMPLES; i++) {
+ count[i] = pit_expect_msb1(0xfe -i, tsc+i, delta+i);
+ if (count[i] <= 5)
+ break;
+ if (inb(0x42) != 0xfd - i)
+ break;
+ }
+ prev = tsc[0];
+ for (j = 0; j < i; j++) {
+ printk("PIT edge at %12llu, delta %7llu, range %6lu, iter %u\n",
+ tsc[j], tsc[j] - prev, delta[j], count[j]);
+ prev = tsc[j];
+ }
+ }
+
+ /* Once more, with the RTC */
+ spin_lock_irqsave(&rtc_lock, flags);
+
+ lock_cmos_prefix(RTC_REG_C);
+/* This is skanky stuff that requries rewritten RTC locking to do properly */
+ outb(RTC_REG_B, RTC_PORT(0));
+ saved_b = inb(RTC_PORT(1));
+ outb(saved_b & 7, RTC_PORT(1)); /* Clear interrupt enables */
+
+ outb(RTC_REG_A, RTC_PORT(0));
+ saved_a = inb(RTC_PORT(1));
+ outb((saved_a & 0xf0) | 3, RTC_PORT(1)); /* Set 8 kHz rate */
+/* End of skanky stuff */
+
+ outb(RTC_REG_C, RTC_PORT(0));
+ inb(RTC_PORT(1)); /* Clear any pending */
+
+ for (i = 0; i < SAMPLES; i++) {
+ count[i] = rtc_wait_bit(tsc+i, delta+i);
+ if (count[i] <= 3)
+ break;
+ if (inb(RTC_PORT(1)) & RTC_PF)
+ break;
+ }
+
+ outb(RTC_REG_A, RTC_PORT(0));
+ outb(saved_a, RTC_PORT(1));
+ outb(RTC_REG_B, RTC_PORT(0));
+ outb(saved_b, RTC_PORT(1));
+
+ lock_cmos_suffix(RTC_REG_C);
+
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ {
+ int j;
+ u64 prev = tsc[0];
+ for (j = 0; j < i; j++) {
+ printk("RTC edge at %12llu, delta %7llu, range %6lu, iter %u\n",
+ tsc[j], tsc[j] - prev, delta[j], count[j]);
+ prev = tsc[j];
+ }
+ }
+}
+
/*
* How many MSB values do we want to see? We aim for
* a maximum error rate of 500ppm (in practice the
@@ -570,6 +724,8 @@ static unsigned long quick_pit_calibrate(void)
/* Set the Gate high, disable speaker */
outb((inb(0x61) & ~0x02) | 0x01, 0x61);

+pit_test();
+
/*
* Counter 2, mode 0 (one-shot), binary count
*
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/