linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* alpha - generic_init_pit - why using RTC for calibration?
@ 2001-06-29 12:20 Oleg I. Vdovikin
  2001-06-29 17:19 ` Ivan Kokshaysky
  0 siblings, 1 reply; 12+ messages in thread
From: Oleg I. Vdovikin @ 2001-06-29 12:20 UTC (permalink / raw)
  To: linux-kernel

Hello,

    we've a bunch of UP2000/UP2000+ boards (similar to DP264) with 666MHz
EV67 Alphas (we're building large Alpha cluster). And we're regulary see
"HWRPB cycle frequency bogus" and the measured value for the speed in the
range of 519 MHz - 666 MHz. And this value changes in this range from boot
to boot. So why this happens???

    Initialy we've an idea this boards has frequency stability problem. But
then I've decided to add simple recalculation for est_cycle_freq on every
1024 ticks which happens on boot processor (I've used rpcc for the
counting). I've added 10 lines to the timer_interrupt function. And I was
really wondered: the clock are rock solid - near 666 MHz and +- 1Khz
stability (I'm thinking it's some non constant overhead in the irq
handlers).

    So, I've looked deeper. And here is the question: why using RTC for
calibration and UIP bit? This bit guarantees nothing - the specs said when
it's raised to 1 if clock update occures in the ~244 ms! But it does not
said this happens regulary in the same time for this 244 ms!

    So, the final question: why we're not using the aproach which is used by
x86 time.c? I.e. why not to use CTC channel 2 for calibration?

    Please correct me, if there is something wrong.

Thanks,
    Oleg.


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: alpha - generic_init_pit - why using RTC for calibration?
  2001-06-29 12:20 alpha - generic_init_pit - why using RTC for calibration? Oleg I. Vdovikin
@ 2001-06-29 17:19 ` Ivan Kokshaysky
  2001-07-02  9:52   ` Oleg I. Vdovikin
  2001-07-04 18:45   ` [patch] " Richard Henderson
  0 siblings, 2 replies; 12+ messages in thread
From: Ivan Kokshaysky @ 2001-06-29 17:19 UTC (permalink / raw)
  To: Oleg I. Vdovikin; +Cc: Richard Henderson, linux-kernel

On Fri, Jun 29, 2001 at 04:20:59PM +0400, Oleg I. Vdovikin wrote:
>     we've a bunch of UP2000/UP2000+ boards (similar to DP264) with 666MHz
> EV67 Alphas (we're building large Alpha cluster). And we're regulary see
> "HWRPB cycle frequency bogus" and the measured value for the speed in the
> range of 519 MHz - 666 MHz. And this value changes in this range from boot
> to boot. So why this happens???

This is known problem with Cypress cy82c693 SIO. The RTC on this chip
sometimes need a very long time (up to several minutes) to settle down
after reset/power-up. But I thought it's fixed on newer systems with
"ub" revision of the chip... :-(

>     So, the final question: why we're not using the aproach which is used by
> x86 time.c? I.e. why not to use CTC channel 2 for calibration?

Good idea. The patch below works reliably on my sx164.

Ivan.

--- 2.4.6-pre5/arch/alpha/kernel/time.c	Mon Nov 13 06:27:11 2000
+++ linux/arch/alpha/kernel/time.c	Fri Jun 29 20:58:09 2001
@@ -169,6 +169,63 @@ common_init_rtc(void)
 	init_rtc_irq();
 }
 
+/*
+ * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from
+ * arch/i386/time.c.
+ */
+
+#define CALIBRATE_LATCH	(52 * LATCH)
+#define CALIBRATE_TIME	(52 * 1000020 / HZ)
+
+static unsigned long __init
+calibrate_cc(void)
+{
+	int cc;
+	unsigned long count = 0;
+
+       /* Set the Gate high, disable speaker */
+	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+	/*
+	 * Now let's take care of CTC channel 2
+	 *
+	 * Set the Gate high, program CTC channel 2 for mode 0,
+	 * (interrupt on terminal count mode), binary count,
+	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+	 */
+	outb(0xb0, 0x43);			/* binary, mode 0, LSB/MSB, Ch 2 */
+	outb(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */
+	outb(CALIBRATE_LATCH >> 8, 0x42);	/* MSB of count */
+
+	cc = rpcc();
+	do {
+		count++;
+	} while ((inb(0x61) & 0x20) == 0);
+	cc = rpcc() - cc;
+
+	/* Error: ECTCNEVERSET */
+	if (count <= 1)
+		goto bad_ctc;
+
+	/* Error: ECPUTOOFAST */
+	if (count >> 32)
+		goto bad_ctc;
+
+	/* Error: ECPUTOOSLOW */
+	if (cc <= CALIBRATE_TIME)
+		goto bad_ctc;
+
+	return ((long)cc * 1000000) / CALIBRATE_TIME;
+
+	/*
+	 * The CTC wasn't reliable: we got a hit on the very first read,
+	 * or the CPU was so fast/slow that the quotient wouldn't fit in
+	 * 32 bits..
+	 */
+bad_ctc:
+	return 0;
+}
+
 void __init
 time_init(void)
 {
@@ -176,6 +233,9 @@ time_init(void)
 	unsigned long cycle_freq, one_percent;
 	long diff;
 
+	/* Calibrate CPU clock -- attempt #1. If this fails, use RTC. */
+	if (!est_cycle_freq)
+		est_cycle_freq = calibrate_cc();
 	/*
 	 * The Linux interpretation of the CMOS clock register contents:
 	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: alpha - generic_init_pit - why using RTC for calibration?
  2001-06-29 17:19 ` Ivan Kokshaysky
@ 2001-07-02  9:52   ` Oleg I. Vdovikin
  2001-07-03 13:06     ` Oleg I. Vdovikin
  2001-07-04 18:45   ` [patch] " Richard Henderson
  1 sibling, 1 reply; 12+ messages in thread
From: Oleg I. Vdovikin @ 2001-07-02  9:52 UTC (permalink / raw)
  To: Ivan Kokshaysky, Richard Henderson; +Cc: linux-kernel

Ivan, thanks. I will minorly adjust the patch, prepare it for 2.2.x series
and then post it.

Thanks,
    Oleg.

P.S. Richard, any thoughts?

----- Original Message -----
From: "Ivan Kokshaysky" <ink@jurassic.park.msu.ru>
To: "Oleg I. Vdovikin" <vdovikin@jscc.ru>
Cc: "Richard Henderson" <rth@twiddle.net>; <linux-kernel@vger.kernel.org>
Sent: Friday, June 29, 2001 9:19 PM
Subject: Re: alpha - generic_init_pit - why using RTC for calibration?


> On Fri, Jun 29, 2001 at 04:20:59PM +0400, Oleg I. Vdovikin wrote:
> >     we've a bunch of UP2000/UP2000+ boards (similar to DP264) with
666MHz
> > EV67 Alphas (we're building large Alpha cluster). And we're regulary see
> > "HWRPB cycle frequency bogus" and the measured value for the speed in
the
> > range of 519 MHz - 666 MHz. And this value changes in this range from
boot
> > to boot. So why this happens???
>
> This is known problem with Cypress cy82c693 SIO. The RTC on this chip
> sometimes need a very long time (up to several minutes) to settle down
> after reset/power-up. But I thought it's fixed on newer systems with
> "ub" revision of the chip... :-(
>
> >     So, the final question: why we're not using the aproach which is
used by
> > x86 time.c? I.e. why not to use CTC channel 2 for calibration?
>
> Good idea. The patch below works reliably on my sx164.
>
> Ivan.
>
> --- 2.4.6-pre5/arch/alpha/kernel/time.c Mon Nov 13 06:27:11 2000
> +++ linux/arch/alpha/kernel/time.c Fri Jun 29 20:58:09 2001
> @@ -169,6 +169,63 @@ common_init_rtc(void)
>   init_rtc_irq();
>  }
>
> +/*
> + * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from
> + * arch/i386/time.c.
> + */
> +
> +#define CALIBRATE_LATCH (52 * LATCH)
> +#define CALIBRATE_TIME (52 * 1000020 / HZ)
> +
> +static unsigned long __init
> +calibrate_cc(void)
> +{
> + int cc;
> + unsigned long count = 0;
> +
> +       /* Set the Gate high, disable speaker */
> + outb((inb(0x61) & ~0x02) | 0x01, 0x61);
> +
> + /*
> + * Now let's take care of CTC channel 2
> + *
> + * Set the Gate high, program CTC channel 2 for mode 0,
> + * (interrupt on terminal count mode), binary count,
> + * load 5 * LATCH count, (LSB and MSB) to begin countdown.
> + */
> + outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
> + outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
> + outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
> +
> + cc = rpcc();
> + do {
> + count++;
> + } while ((inb(0x61) & 0x20) == 0);
> + cc = rpcc() - cc;
> +
> + /* Error: ECTCNEVERSET */
> + if (count <= 1)
> + goto bad_ctc;
> +
> + /* Error: ECPUTOOFAST */
> + if (count >> 32)
> + goto bad_ctc;
> +
> + /* Error: ECPUTOOSLOW */
> + if (cc <= CALIBRATE_TIME)
> + goto bad_ctc;
> +
> + return ((long)cc * 1000000) / CALIBRATE_TIME;
> +
> + /*
> + * The CTC wasn't reliable: we got a hit on the very first read,
> + * or the CPU was so fast/slow that the quotient wouldn't fit in
> + * 32 bits..
> + */
> +bad_ctc:
> + return 0;
> +}
> +
>  void __init
>  time_init(void)
>  {
> @@ -176,6 +233,9 @@ time_init(void)
>   unsigned long cycle_freq, one_percent;
>   long diff;
>
> + /* Calibrate CPU clock -- attempt #1. If this fails, use RTC. */
> + if (!est_cycle_freq)
> + est_cycle_freq = calibrate_cc();
>   /*
>   * The Linux interpretation of the CMOS clock register contents:
>   * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
>


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: alpha - generic_init_pit - why using RTC for calibration?
  2001-07-02  9:52   ` Oleg I. Vdovikin
@ 2001-07-03 13:06     ` Oleg I. Vdovikin
  0 siblings, 0 replies; 12+ messages in thread
From: Oleg I. Vdovikin @ 2001-07-03 13:06 UTC (permalink / raw)
  To: Alan Cox, Ivan Kokshaysky; +Cc: linux-kernel, Richard Henderson

[-- Attachment #1: Type: text/plain, Size: 2092 bytes --]

    Here is the patch against the buggy Cypress RTC which is found on some
Alpha boards. It's tested with 2.2.16 & 2.2.19 kernels and as seems should
work with 2.4.x kernels. This patch differs from initial Ivan's version by
the "cc" variable type & different calibrate divisor usage for better
accuracy.

    Please consider applying this patch against the 2.2.x tree. It's really
needed due to overall performance reasons.

Thanks,
    Oleg.

--- linux/arch/alpha/kernel/time.c.orig Mon Jul  2 14:05:09 2001
+++ linux/arch/alpha/kernel/time.c Mon Jul  2 15:47:45 2001
@@ -231,6 +231,49 @@
  outb(0x13, 0x42);
 }

+/*
+ * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from
+ * arch/i386/time.c.
+ */
+
+#define CALIBRATE_DIVISOR 0xffff
+
+static unsigned long __init
+calibrate_cc(void)
+{
+ unsigned int cc;
+ unsigned long count = 0;
+
+ /* Set the Gate high, disable speaker */
+ outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+ /*
+  * Now let's take care of CTC channel 2
+  *
+  * Set the Gate high, program CTC channel 2 for mode 0,
+  * (interrupt on terminal count mode), binary count,
+  * load maximum divisor we can get for accuracy - 65535
+  */
+
+ outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
+ outb(CALIBRATE_DIVISOR & 0xff, 0x42); /* LSB of count */
+ outb(CALIBRATE_DIVISOR >> 8, 0x42); /* MSB of count */
+
+ /* we still should not hang if timer not runing or N/A */
+ for (cc = rpcc(); (inb(0x61) & 0x20) == 0 && !(count >> 32); count++);
+
+ /* cycles delta */
+ cc = rpcc() - cc;
+
+ /* check for the reliable result */
+ if ((count < 1) || (count >> 32))
+     return 0;
+
+ /* and the final result in HZ */
+ return ((unsigned long)cc * CLOCK_TICK_RATE) / CALIBRATE_DIVISOR;
+}
+
+
 void
 time_init(void)
 {
@@ -239,6 +282,10 @@
  unsigned long cycle_freq, ppm_error;
  long diff;

+ /* Calibrate CPU clock using CTC. If this fails, use RTC. */
+ if (!est_cycle_freq)
+     est_cycle_freq = calibrate_cc();
+
  /*
   * The Linux interpretation of the CMOS clock register contents:
   * When the Update-In-Progress (UIP) flag goes from 1 to 0, the



[-- Attachment #2: linux-2.2.x.rtc.patch --]
[-- Type: application/octet-stream, Size: 1972 bytes --]

--- linux/arch/alpha/kernel/time.c.orig	Mon Jul  2 14:05:09 2001
+++ linux/arch/alpha/kernel/time.c	Mon Jul  2 15:47:45 2001
@@ -231,6 +231,49 @@
 	outb(0x13, 0x42);
 }
 
+/*
+ * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from
+ * arch/i386/time.c.
+ */
+
+#define CALIBRATE_DIVISOR	0xffff
+
+static unsigned long __init
+calibrate_cc(void)
+{
+	unsigned int cc;
+	unsigned long count = 0;
+	
+	/* Set the Gate high, disable speaker */
+	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+	
+	/*
+	 * Now let's take care of CTC channel 2
+	 *
+	 * Set the Gate high, program CTC channel 2 for mode 0,
+	 * (interrupt on terminal count mode), binary count,
+	 * load maximum divisor we can get for accuracy - 65535
+	 */
+	
+	outb(0xb0, 0x43);	/* binary, mode 0, LSB/MSB, Ch 2 */
+	outb(CALIBRATE_DIVISOR & 0xff, 0x42);	/* LSB of count */
+	outb(CALIBRATE_DIVISOR >> 8, 0x42);	/* MSB of count */
+
+	/* we still should not hang if timer not runing or N/A */
+	for (cc = rpcc(); (inb(0x61) & 0x20) == 0 && !(count >> 32); count++);
+
+	/* cycles delta */
+	cc = rpcc() - cc;
+	
+	/* check for the reliable result */
+	if ((count < 1) || (count >> 32))
+	    return 0;
+
+	/* and the final result in HZ */
+	return ((unsigned long)cc * CLOCK_TICK_RATE) / CALIBRATE_DIVISOR;
+}
+
+
 void
 time_init(void)
 {
@@ -239,6 +282,10 @@
 	unsigned long cycle_freq, ppm_error;
 	long diff;
 
+	/* Calibrate CPU clock using CTC. If this fails, use RTC. */
+	if (!est_cycle_freq)
+	    est_cycle_freq = calibrate_cc();
+
 	/*
 	 * The Linux interpretation of the CMOS clock register contents:
 	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
@@ -275,7 +322,7 @@
 	if (diff < 0)
 		diff = -diff;
 	ppm_error = (diff * 1000000L) / cycle_freq;
-#if 0
+#if 1
 	printk("Alpha clock init: HWRPB %lu, Measured %lu, error=%lu ppm.\n",
 	       hwrpb->cycle_freq, est_cycle_freq, ppm_error);
 #endif

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch] Re: alpha - generic_init_pit - why using RTC for calibration?
  2001-06-29 17:19 ` Ivan Kokshaysky
  2001-07-02  9:52   ` Oleg I. Vdovikin
@ 2001-07-04 18:45   ` Richard Henderson
  2001-07-05  7:14     ` Oleg I. Vdovikin
  1 sibling, 1 reply; 12+ messages in thread
From: Richard Henderson @ 2001-07-04 18:45 UTC (permalink / raw)
  To: Ivan Kokshaysky, alan, torvalds; +Cc: Oleg I. Vdovikin, linux-kernel

On Fri, Jun 29, 2001 at 09:19:31PM +0400, Ivan Kokshaysky wrote:
> Good idea. The patch below works reliably on my sx164.

Reasonable.  Here I've cleaned up time_init a tad as well.


r~



--- arch/alpha/kernel/time.c.orig	Fri Jun 29 11:24:03 2001
+++ arch/alpha/kernel/time.c	Fri Jun 29 11:35:52 2001
@@ -169,6 +169,77 @@ common_init_rtc(void)
 	init_rtc_irq();
 }
 
+/*
+ * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from
+ * arch/i386/time.c.
+ */
+
+#define CALIBRATE_LATCH	(52 * LATCH)
+#define CALIBRATE_TIME	(52 * 1000020 / HZ)
+
+static unsigned long __init
+calibrate_cc_with_pic(void)
+{
+	int cc;
+	unsigned long count = 0;
+
+	/* Set the Gate high, disable speaker */
+	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+
+	/*
+	 * Now let's take care of CTC channel 2
+	 *
+	 * Set the Gate high, program CTC channel 2 for mode 0,
+	 * (interrupt on terminal count mode), binary count,
+	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+	 */
+	outb(0xb0, 0x43);		/* binary, mode 0, LSB/MSB, Ch 2 */
+	outb(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */
+	outb(CALIBRATE_LATCH >> 8, 0x42);	/* MSB of count */
+
+	cc = rpcc();
+	do {
+		count++;
+	} while ((inb(0x61) & 0x20) == 0);
+	cc = rpcc() - cc;
+
+	/* Error: ECTCNEVERSET */
+	if (count <= 1)
+		goto bad_ctc;
+
+	/* Error: ECPUTOOFAST */
+	if (count >> 32)
+		goto bad_ctc;
+
+	/* Error: ECPUTOOSLOW */
+	if (cc <= CALIBRATE_TIME)
+		goto bad_ctc;
+
+	return ((long)cc * 1000000) / CALIBRATE_TIME;
+
+	/*
+	 * The CTC wasn't reliable: we got a hit on the very first read,
+	 * or the CPU was so fast/slow that the quotient wouldn't fit in
+	 * 32 bits..
+	 */
+ bad_ctc:
+	return 0;
+}
+
+/* The Linux interpretation of the CMOS clock register contents:
+   When the Update-In-Progress (UIP) flag goes from 1 to 0, the
+   RTC registers show the second which has precisely just started.
+   Let's hope other operating systems interpret the RTC the same way.  */
+
+static unsigned long __init
+rpcc_after_update_in_progress(void)
+{
+	do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
+	do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+
+	return rpcc();
+}
+
 void __init
 time_init(void)
 {
@@ -176,24 +247,15 @@ time_init(void)
 	unsigned long cycle_freq, one_percent;
 	long diff;
 
-	/*
-	 * The Linux interpretation of the CMOS clock register contents:
-	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
-	 * RTC registers show the second which has precisely just started.
-	 * Let's hope other operating systems interpret the RTC the same way.
-	 */
-	do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
-	do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
+	/* Calibrate CPU clock -- attempt #1.  */
+	if (!est_cycle_freq)
+		est_cycle_freq = calibrate_cc_with_pic();
 
-	/* Read cycle counter exactly on falling edge of update flag */
-	cc1 = rpcc();
+	cc1 = rpcc_after_update_in_progress();
 
+	/* Calibrate CPU clock -- attempt #2.  */
 	if (!est_cycle_freq) {
-		/* Sometimes the hwrpb->cycle_freq value is bogus. 
-		   Go another round to check up on it and see.  */
-		do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
-		do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
-		cc2 = rpcc();
+		cc2 = rpcc_after_update_in_progress();
 		est_cycle_freq = cc2 - cc1;
 		cc1 = cc2;
 	}

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch] Re: alpha - generic_init_pit - why using RTC for calibration?
  2001-07-04 18:45   ` [patch] " Richard Henderson
@ 2001-07-05  7:14     ` Oleg I. Vdovikin
       [not found]       ` <3B441618.638A3FC@mandrakesoft.com>
  2001-07-05  9:43       ` Ivan Kokshaysky
  0 siblings, 2 replies; 12+ messages in thread
From: Oleg I. Vdovikin @ 2001-07-05  7:14 UTC (permalink / raw)
  To: Richard Henderson, Ivan Kokshaysky, alan, torvalds; +Cc: linux-kernel

    Richard, thanks. But please use calibrate_cc version which I've submited
as a patch - it gives more accuracy with maximum latch we can ever use and
has cc's type changed to 'unsigned int' to prevent problems when rpcc
overflows.

Oleg.

----- Original Message -----
From: "Richard Henderson" <rth@twiddle.net>
To: "Ivan Kokshaysky" <ink@jurassic.park.msu.ru>; <alan@redhat.com>;
<torvalds@transmeta.com>
Cc: "Oleg I. Vdovikin" <vdovikin@jscc.ru>; <linux-kernel@vger.kernel.org>
Sent: Wednesday, July 04, 2001 10:45 PM
Subject: [patch] Re: alpha - generic_init_pit - why using RTC for
calibration?


> On Fri, Jun 29, 2001 at 09:19:31PM +0400, Ivan Kokshaysky wrote:
> > Good idea. The patch below works reliably on my sx164.
>
> Reasonable.  Here I've cleaned up time_init a tad as well.
>
>
> r~
>
>
>
> --- arch/alpha/kernel/time.c.orig Fri Jun 29 11:24:03 2001
> +++ arch/alpha/kernel/time.c Fri Jun 29 11:35:52 2001
> @@ -169,6 +169,77 @@ common_init_rtc(void)
>   init_rtc_irq();
>  }
>
> +/*
> + * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from
> + * arch/i386/time.c.
> + */
> +
> +#define CALIBRATE_LATCH (52 * LATCH)
> +#define CALIBRATE_TIME (52 * 1000020 / HZ)
> +
> +static unsigned long __init
> +calibrate_cc_with_pic(void)
> +{
> + int cc;
> + unsigned long count = 0;
> +
> + /* Set the Gate high, disable speaker */
> + outb((inb(0x61) & ~0x02) | 0x01, 0x61);
> +
> + /*
> + * Now let's take care of CTC channel 2
> + *
> + * Set the Gate high, program CTC channel 2 for mode 0,
> + * (interrupt on terminal count mode), binary count,
> + * load 5 * LATCH count, (LSB and MSB) to begin countdown.
> + */
> + outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
> + outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
> + outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
> +
> + cc = rpcc();
> + do {
> + count++;
> + } while ((inb(0x61) & 0x20) == 0);
> + cc = rpcc() - cc;
> +
> + /* Error: ECTCNEVERSET */
> + if (count <= 1)
> + goto bad_ctc;
> +
> + /* Error: ECPUTOOFAST */
> + if (count >> 32)
> + goto bad_ctc;
> +
> + /* Error: ECPUTOOSLOW */
> + if (cc <= CALIBRATE_TIME)
> + goto bad_ctc;
> +
> + return ((long)cc * 1000000) / CALIBRATE_TIME;
> +
> + /*
> + * The CTC wasn't reliable: we got a hit on the very first read,
> + * or the CPU was so fast/slow that the quotient wouldn't fit in
> + * 32 bits..
> + */
> + bad_ctc:
> + return 0;
> +}
> +
> +/* The Linux interpretation of the CMOS clock register contents:
> +   When the Update-In-Progress (UIP) flag goes from 1 to 0, the
> +   RTC registers show the second which has precisely just started.
> +   Let's hope other operating systems interpret the RTC the same way.  */
> +
> +static unsigned long __init
> +rpcc_after_update_in_progress(void)
> +{
> + do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
> + do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
> +
> + return rpcc();
> +}
> +
>  void __init
>  time_init(void)
>  {
> @@ -176,24 +247,15 @@ time_init(void)
>   unsigned long cycle_freq, one_percent;
>   long diff;
>
> - /*
> - * The Linux interpretation of the CMOS clock register contents:
> - * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
> - * RTC registers show the second which has precisely just started.
> - * Let's hope other operating systems interpret the RTC the same way.
> - */
> - do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
> - do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
> + /* Calibrate CPU clock -- attempt #1.  */
> + if (!est_cycle_freq)
> + est_cycle_freq = calibrate_cc_with_pic();
>
> - /* Read cycle counter exactly on falling edge of update flag */
> - cc1 = rpcc();
> + cc1 = rpcc_after_update_in_progress();
>
> + /* Calibrate CPU clock -- attempt #2.  */
>   if (!est_cycle_freq) {
> - /* Sometimes the hwrpb->cycle_freq value is bogus.
> -    Go another round to check up on it and see.  */
> - do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
> - do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
> - cc2 = rpcc();
> + cc2 = rpcc_after_update_in_progress();
>   est_cycle_freq = cc2 - cc1;
>   cc1 = cc2;
>   }
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch] Re: alpha - generic_init_pit - why using RTC for  calibration?
       [not found]       ` <3B441618.638A3FC@mandrakesoft.com>
@ 2001-07-05  8:36         ` Oleg I. Vdovikin
  2001-07-05  8:47           ` Jeff Garzik
  0 siblings, 1 reply; 12+ messages in thread
From: Oleg I. Vdovikin @ 2001-07-05  8:36 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: Richard Henderson, alan, torvalds, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 577 bytes --]

That's it.

Please also include my old rtc patch for 2.2.x series into official 2.2.20
kernel.

Thanks,
    Oleg.

-------------
From: "Jeff Garzik" <jgarzik@mandrakesoft.com>
Subject: Re: [patch] Re: alpha - generic_init_pit - why using RTC for
calibration?

> Oleg,
>
> The official kernel now carries Richard's version.  Can you post a diff
> on linux-kernel against version 2.4.7-pre2 perhaps, which cleans up
> Richard's code to yours?
> --
> Jeff Garzik      | Thalidomide, eh?
> Building 1024    | So you're saying the eggplant has an accomplice?
> MandrakeSoft     |
>

[-- Attachment #2: linux-2.2.x.rtc.patch --]
[-- Type: application/octet-stream, Size: 1972 bytes --]

--- linux/arch/alpha/kernel/time.c.orig	Mon Jul  2 14:05:09 2001
+++ linux/arch/alpha/kernel/time.c	Mon Jul  2 15:47:45 2001
@@ -231,6 +231,49 @@
 	outb(0x13, 0x42);
 }
 
+/*
+ * Calibrate CPU clock using legacy 8254 timer/counter. Stolen from
+ * arch/i386/time.c.
+ */
+
+#define CALIBRATE_DIVISOR	0xffff
+
+static unsigned long __init
+calibrate_cc(void)
+{
+	unsigned int cc;
+	unsigned long count = 0;
+	
+	/* Set the Gate high, disable speaker */
+	outb((inb(0x61) & ~0x02) | 0x01, 0x61);
+	
+	/*
+	 * Now let's take care of CTC channel 2
+	 *
+	 * Set the Gate high, program CTC channel 2 for mode 0,
+	 * (interrupt on terminal count mode), binary count,
+	 * load maximum divisor we can get for accuracy - 65535
+	 */
+	
+	outb(0xb0, 0x43);	/* binary, mode 0, LSB/MSB, Ch 2 */
+	outb(CALIBRATE_DIVISOR & 0xff, 0x42);	/* LSB of count */
+	outb(CALIBRATE_DIVISOR >> 8, 0x42);	/* MSB of count */
+
+	/* we still should not hang if timer not runing or N/A */
+	for (cc = rpcc(); (inb(0x61) & 0x20) == 0 && !(count >> 32); count++);
+
+	/* cycles delta */
+	cc = rpcc() - cc;
+	
+	/* check for the reliable result */
+	if ((count < 1) || (count >> 32))
+	    return 0;
+
+	/* and the final result in HZ */
+	return ((unsigned long)cc * CLOCK_TICK_RATE) / CALIBRATE_DIVISOR;
+}
+
+
 void
 time_init(void)
 {
@@ -239,6 +282,10 @@
 	unsigned long cycle_freq, ppm_error;
 	long diff;
 
+	/* Calibrate CPU clock using CTC. If this fails, use RTC. */
+	if (!est_cycle_freq)
+	    est_cycle_freq = calibrate_cc();
+
 	/*
 	 * The Linux interpretation of the CMOS clock register contents:
 	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the
@@ -275,7 +322,7 @@
 	if (diff < 0)
 		diff = -diff;
 	ppm_error = (diff * 1000000L) / cycle_freq;
-#if 0
+#if 1
 	printk("Alpha clock init: HWRPB %lu, Measured %lu, error=%lu ppm.\n",
 	       hwrpb->cycle_freq, est_cycle_freq, ppm_error);
 #endif

[-- Attachment #3: linux-2.4.7pre2.rtc.patch --]
[-- Type: application/octet-stream, Size: 1905 bytes --]

--- arch/alpha/kernel/time.c.orig	Thu Jul  5 12:18:48 2001
+++ arch/alpha/kernel/time.c	Thu Jul  5 12:24:11 2001
@@ -174,13 +174,12 @@
  * arch/i386/time.c.
  */
 
-#define CALIBRATE_LATCH	(52 * LATCH)
-#define CALIBRATE_TIME	(52 * 1000020 / HZ)
+#define CALIBRATE_LATCH	0xffff
 
 static unsigned long __init
 calibrate_cc_with_pic(void)
 {
-	int cc;
+	unsigned int cc;
 	unsigned long count = 0;
 
 	/* Set the Gate high, disable speaker */
@@ -191,39 +190,24 @@
 	 *
 	 * Set the Gate high, program CTC channel 2 for mode 0,
 	 * (interrupt on terminal count mode), binary count,
-	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+	 * load maximum divisor we can get for accuracy - 65535
 	 */
 	outb(0xb0, 0x43);		/* binary, mode 0, LSB/MSB, Ch 2 */
 	outb(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */
 	outb(CALIBRATE_LATCH >> 8, 0x42);	/* MSB of count */
-
-	cc = rpcc();
-	do {
-		count++;
-	} while ((inb(0x61) & 0x20) == 0);
+	
+	/* we still should not hang if timer not runing or N/A */
+	for (cc = rpcc(); (inb(0x61) & 0x20) == 0 && !(count >> 32); count++);
+	
+	/* cycles delta */
 	cc = rpcc() - cc;
-
-	/* Error: ECTCNEVERSET */
-	if (count <= 1)
-		goto bad_ctc;
-
-	/* Error: ECPUTOOFAST */
-	if (count >> 32)
-		goto bad_ctc;
-
-	/* Error: ECPUTOOSLOW */
-	if (cc <= CALIBRATE_TIME)
-		goto bad_ctc;
-
-	return ((long)cc * 1000000) / CALIBRATE_TIME;
-
-	/*
-	 * The CTC wasn't reliable: we got a hit on the very first read,
-	 * or the CPU was so fast/slow that the quotient wouldn't fit in
-	 * 32 bits..
-	 */
- bad_ctc:
-	return 0;
+	
+	/* check for the reliable result */
+	if ((count < 1) || (count >> 32))
+		return 0;
+		
+	/* and the final result in HZ */
+	return ((unsigned long)cc * CLOCK_TICK_RATE) / CALIBRATE_LATCH;
 }
 
 /* The Linux interpretation of the CMOS clock register contents:

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch] Re: alpha - generic_init_pit - why using RTC for   calibration?
  2001-07-05  8:36         ` Oleg I. Vdovikin
@ 2001-07-05  8:47           ` Jeff Garzik
  2001-07-06  8:45             ` Oleg I. Vdovikin
  0 siblings, 1 reply; 12+ messages in thread
From: Jeff Garzik @ 2001-07-05  8:47 UTC (permalink / raw)
  To: Oleg I. Vdovikin; +Cc: Richard Henderson, alan, torvalds, linux-kernel

Oleg,

How is this relative to HZ, when you remove all references to HZ?

> -#define CALIBRATE_LATCH        (52 * LATCH)
> -#define CALIBRATE_TIME (52 * 1000020 / HZ)
> +#define CALIBRATE_LATCH        0xffff
[...]
> +       /* and the final result in HZ */
> +       return ((unsigned long)cc * CLOCK_TICK_RATE) / CALIBRATE_LATCH;

and in asm-alpha/timex.h,
> #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */

-- 
Jeff Garzik      | Thalidomide, eh? 
Building 1024    | So you're saying the eggplant has an accomplice?
MandrakeSoft     |

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch] Re: alpha - generic_init_pit - why using RTC for calibration?
  2001-07-05  7:14     ` Oleg I. Vdovikin
       [not found]       ` <3B441618.638A3FC@mandrakesoft.com>
@ 2001-07-05  9:43       ` Ivan Kokshaysky
  2001-07-06  9:03         ` Oleg I. Vdovikin
  1 sibling, 1 reply; 12+ messages in thread
From: Ivan Kokshaysky @ 2001-07-05  9:43 UTC (permalink / raw)
  To: Oleg I. Vdovikin; +Cc: linux-kernel

On Thu, Jul 05, 2001 at 11:14:19AM +0400, Oleg I. Vdovikin wrote:
>     Richard, thanks. But please use calibrate_cc version which I've submited
> as a patch - it gives more accuracy with maximum latch we can ever use and

With both variants even on a 166MHz CPU you'll get above 1e-7 precision,
which is way above accuracy of any crystal oscillator.

> has cc's type changed to 'unsigned int' to prevent problems when rpcc
> overflows.

The only difference is that you'll have extra 'zap' instruction converting
'unsigned int' to 'unsigned long'.

Ivan.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch] Re: alpha - generic_init_pit - why using RTC for   calibration?
  2001-07-05  8:47           ` Jeff Garzik
@ 2001-07-06  8:45             ` Oleg I. Vdovikin
  0 siblings, 0 replies; 12+ messages in thread
From: Oleg I. Vdovikin @ 2001-07-06  8:45 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: Richard Henderson, Ivan Kokshaysky, alan, torvalds, linux-kernel

Jeff,

    The things are pretty simple (HZ - in real should be "Hz", cause HZ are
fixed for Alpha, HZ = 1024 Hz) :
        Hz = cc / calibration_time

    cc == rpcc() at end - rpcc() at begin
    calibration_time = (CLOCK_TICK_RATE / CALIBRATE_LATCH).

    So there is nothing wrong - clock ticks with CLOCK_TICK_RATE and we've a
divisor equal to CALIBRATE_LATCH. So the time interval elapses after
(CLOCK_TICK_RATE / CALIBRATE_LATCH) seconds and the CPU performs 'cc'
cycles.

    That's all. And these really works. ;-))

    About x86 style code - don't forget what LATCH defined as follows in
linux/timex.h:

#define LATCH  ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */

Regards,
    Oleg.

> Oleg,
>
> How is this relative to HZ, when you remove all references to HZ?
>
> > -#define CALIBRATE_LATCH        (52 * LATCH)
> > -#define CALIBRATE_TIME (52 * 1000020 / HZ)
> > +#define CALIBRATE_LATCH        0xffff
> [...]
> > +       /* and the final result in HZ */
> > +       return ((unsigned long)cc * CLOCK_TICK_RATE) / CALIBRATE_LATCH;
>
> and in asm-alpha/timex.h,
> > #define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
>
> --
> Jeff Garzik      | Thalidomide, eh?
> Building 1024    | So you're saying the eggplant has an accomplice?
> MandrakeSoft     |
>


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch] Re: alpha - generic_init_pit - why using RTC for calibration?
  2001-07-05  9:43       ` Ivan Kokshaysky
@ 2001-07-06  9:03         ` Oleg I. Vdovikin
  2001-07-06 12:00           ` Ivan Kokshaysky
  0 siblings, 1 reply; 12+ messages in thread
From: Oleg I. Vdovikin @ 2001-07-06  9:03 UTC (permalink / raw)
  To: Ivan Kokshaysky; +Cc: linux-kernel

> With both variants even on a 166MHz CPU you'll get above 1e-7 precision,
> which is way above accuracy of any crystal oscillator.
    No, this is not so - this line

return ((long)cc * 1000000) / CALIBRATE_TIME;

    truncates the result to the MHZ because of the '* 1000000' statement (cc
is an int value, so you just loose the precision). This works ok for x86,
because x86 uses this value with an accuracy to MHz, but this is not enough
for Alphas (see gettimeofday - we're relies rpcc for calculation). Try to
pass 'cycle=666000000' to your kernel and when run ntp - you're out of luck
for clock sync.

    But the most innacuracy comes from

#define CALIBRATE_TIME (5 * 1000020/HZ)

    1000020 != CLOCK_TICK_RATE - why? So, with this stuff we're loosing more
than 100 KHz (again, this ok for x86) ....

>
> > has cc's type changed to 'unsigned int' to prevent problems when rpcc
> > overflows.
>
> The only difference is that you'll have extra 'zap' instruction converting
> 'unsigned int' to 'unsigned long'.
    No, this is not so. The problem is with the sign bit of int, so,

    (long)(int)0x80000000 != (long)(unsigned int)0x80000000, and
(long)(int)0x80000000 < 0 and you will get negative frequency value (yes we
current boxes we're not overflowing, but let's look for the future). Funny?
;-))

Oleg.

P.S. Ivan, you can reach me by dialing 938-6412 in Moscow.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch] Re: alpha - generic_init_pit - why using RTC for calibration?
  2001-07-06  9:03         ` Oleg I. Vdovikin
@ 2001-07-06 12:00           ` Ivan Kokshaysky
  0 siblings, 0 replies; 12+ messages in thread
From: Ivan Kokshaysky @ 2001-07-06 12:00 UTC (permalink / raw)
  To: Oleg I. Vdovikin; +Cc: linux-kernel

On Fri, Jul 06, 2001 at 01:03:38PM +0400, Oleg I. Vdovikin wrote:
> return ((long)cc * 1000000) / CALIBRATE_TIME;
> 
>     truncates the result to the MHZ because of the '* 1000000' statement (cc
> is an int value, so you just loose the precision).

No, this is ok. 'cc' is long here, and CALIBRATE_TIME is in microseconds,
hence '* 1000000'.

> This works ok for x86,
> because x86 uses this value with an accuracy to MHz, but this is not enough
> for Alphas (see gettimeofday - we're relies rpcc for calculation). Try to
> pass 'cycle=666000000' to your kernel and when run ntp - you're out of luck
> for clock sync.

Hmm, this should be ok. I heard of people who had problems with ntp starting
from 0.5% or more difference between real and estimated clock rates.

>     But the most innacuracy comes from
> 
> #define CALIBRATE_TIME (5 * 1000020/HZ)

With that I agree. All these integer divisions leads to about
%0.02 error.

>     (long)(int)0x80000000 != (long)(unsigned int)0x80000000, and
> (long)(int)0x80000000 < 0 and you will get negative frequency value (yes we
> current boxes we're not overflowing, but let's look for the future).

Oh, I see. So you're arguing for 72 vs. 36 GHz limit. ;-)

> Funny?
> ;-))

Not at all. The future of Alpha is dark... [thanks, Compaq!]

> P.S. Ivan, you can reach me by dialing 938-6412 in Moscow.

Ok. And I can be reached at 930-8952.

Ivan.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2001-07-06 12:00 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2001-06-29 12:20 alpha - generic_init_pit - why using RTC for calibration? Oleg I. Vdovikin
2001-06-29 17:19 ` Ivan Kokshaysky
2001-07-02  9:52   ` Oleg I. Vdovikin
2001-07-03 13:06     ` Oleg I. Vdovikin
2001-07-04 18:45   ` [patch] " Richard Henderson
2001-07-05  7:14     ` Oleg I. Vdovikin
     [not found]       ` <3B441618.638A3FC@mandrakesoft.com>
2001-07-05  8:36         ` Oleg I. Vdovikin
2001-07-05  8:47           ` Jeff Garzik
2001-07-06  8:45             ` Oleg I. Vdovikin
2001-07-05  9:43       ` Ivan Kokshaysky
2001-07-06  9:03         ` Oleg I. Vdovikin
2001-07-06 12:00           ` Ivan Kokshaysky

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).