patch-2.4.14 linux/arch/alpha/kernel/time.c
Next file: linux/arch/alpha/kernel/traps.c
Previous file: linux/arch/alpha/kernel/setup.c
Back to the patch index
Back to the overall index
- Lines: 162
- Date:
Fri Nov 2 17:39:20 2001
- Orig file:
v2.4.13/linux/arch/alpha/kernel/time.c
- Orig date:
Tue Oct 9 17:06:51 2001
diff -u --recursive --new-file v2.4.13/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
@@ -169,6 +169,63 @@
init_rtc_irq();
}
+
+/* Validate a computed cycle counter result against the known bounds for
+ the given processor core. There's too much brokenness in the way of
+ timing hardware for any one method to work everywhere. :-(
+
+ Return 0 if the result cannot be trusted, otherwise return the argument. */
+
+static unsigned long __init
+validate_cc_value(unsigned long cc)
+{
+ static struct bounds {
+ unsigned int min, max;
+ } cpu_hz[] __initdata = {
+ [EV3_CPU] = { 50000000, 200000000 }, /* guess */
+ [EV4_CPU] = { 150000000, 300000000 },
+ [LCA4_CPU] = { 150000000, 300000000 }, /* guess */
+ [EV45_CPU] = { 200000000, 300000000 },
+ [EV5_CPU] = { 266000000, 333333333 },
+ [EV56_CPU] = { 366000000, 667000000 },
+ [PCA56_CPU] = { 400000000, 600000000 }, /* guess */
+ [PCA57_CPU] = { 500000000, 600000000 }, /* guess */
+ [EV6_CPU] = { 466000000, 600000000 },
+ [EV67_CPU] = { 600000000, 750000000 },
+ [EV68AL_CPU] = { 750000000, 940000000 },
+ [EV68CB_CPU] = { 1000000000, 1333333333 },
+ /* None of the following are shipping as of 2001-11-01. */
+ [EV68CX_CPU] = { 1000000000, 1700000000 }, /* guess */
+ [EV69_CPU] = { 1000000000, 1700000000 }, /* guess */
+ [EV7_CPU] = { 800000000, 1400000000 }, /* guess */
+ [EV79_CPU] = { 1000000000, 2000000000 }, /* guess */
+ };
+
+ /* Allow for some drift in the crystal. 10MHz is more than enough. */
+ const unsigned int deviation = 10000000;
+
+ struct percpu_struct *cpu;
+ unsigned int index;
+
+ cpu = (struct percpu_struct *)((char*)hwrpb + hwrpb->processor_offset);
+ index = cpu->type & 0xffffffff;
+
+ /* If index out of bounds, no way to validate. */
+ if (index >= sizeof(cpu_hz)/sizeof(cpu_hz[0]))
+ return cc;
+
+ /* If index contains no data, no way to validate. */
+ if (cpu_hz[index].max == 0)
+ return cc;
+
+ if (cc < cpu_hz[index].min - deviation
+ || cc > cpu_hz[index].max + deviation)
+ return 0;
+
+ return cc;
+}
+
+
/*
* Calibrate CPU clock using legacy 8254 timer/counter. Stolen from
* arch/i386/time.c.
@@ -180,8 +237,7 @@
static unsigned long __init
calibrate_cc_with_pic(void)
{
- int cc;
- unsigned long count = 0;
+ int cc, count = 0;
/* Set the Gate high, disable speaker */
outb((inb(0x61) & ~0x02) | 0x01, 0x61);
@@ -200,30 +256,18 @@
cc = rpcc();
do {
count++;
- } while ((inb(0x61) & 0x20) == 0);
+ } while ((inb(0x61) & 0x20) == 0 && count > 0);
cc = rpcc() - cc;
- /* Error: ECTCNEVERSET */
+ /* Error: ECTCNEVERSET or ECPUTOOFAST. */
if (count <= 1)
- goto bad_ctc;
+ return 0;
- /* Error: ECPUTOOFAST */
- if (count >> 32)
- goto bad_ctc;
-
- /* Error: ECPUTOOSLOW */
+ /* Error: ECPUTOOSLOW. */
if (cc <= CALIBRATE_TIME)
- goto bad_ctc;
-
- return ((long)cc * 1000000) / CALIBRATE_TIME;
+ return 0;
- /*
- * 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;
+ return (cc * 1000000UL) / CALIBRATE_TIME;
}
/* The Linux interpretation of the CMOS clock register contents:
@@ -249,31 +293,35 @@
/* Calibrate CPU clock -- attempt #1. */
if (!est_cycle_freq)
- est_cycle_freq = calibrate_cc_with_pic();
+ est_cycle_freq = validate_cc_value(calibrate_cc_with_pic());
cc1 = rpcc_after_update_in_progress();
/* Calibrate CPU clock -- attempt #2. */
if (!est_cycle_freq) {
cc2 = rpcc_after_update_in_progress();
- est_cycle_freq = cc2 - cc1;
+ est_cycle_freq = validate_cc_value(cc2 - cc1);
cc1 = cc2;
}
- /* If the given value is within 1% of what we calculated,
- accept it. Otherwise, use what we found. */
cycle_freq = hwrpb->cycle_freq;
- one_percent = cycle_freq / 100;
- diff = cycle_freq - est_cycle_freq;
- if (diff < 0)
- diff = -diff;
- if (diff > one_percent) {
- cycle_freq = est_cycle_freq;
- printk("HWRPB cycle frequency bogus. Estimated %lu Hz\n",
- cycle_freq);
- }
- else {
- est_cycle_freq = 0;
+ if (est_cycle_freq) {
+ /* If the given value is within 1% of what we calculated,
+ accept it. Otherwise, use what we found. */
+ one_percent = cycle_freq / 100;
+ diff = cycle_freq - est_cycle_freq;
+ if (diff < 0)
+ diff = -diff;
+ if (diff > one_percent) {
+ cycle_freq = est_cycle_freq;
+ printk("HWRPB cycle frequency bogus. "
+ "Estimated %lu Hz\n", cycle_freq);
+ } else {
+ est_cycle_freq = 0;
+ }
+ } else if (! validate_cc_value (cycle_freq)) {
+ printk("HWRPB cycle frequency bogus, "
+ "and unable to estimate a proper value!\n");
}
/* From John Bowman <bowman@math.ualberta.ca>: allow the values
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)