]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/suse-2.6.27.39/patches.arch/x86_64_make_calibrate_APIC_clock_SMI-safe.diff
Fix oinkmaster patch.
[ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.arch / x86_64_make_calibrate_APIC_clock_SMI-safe.diff
CommitLineData
4d1e5b62
AF
1From: Martin Wilck <martin.wilck@fujitsu-siemens.com>
2Subject: x86-64: Make APIC timer calibration SMI-safe
3References: bnc#410452, bnc#535947
4
5APIC timer calibration can be adversely affected if SMI are
6triggered during calibration. Make the calibration algorithm
7more robust to detect and workaround this situation.
8
9This patch isn't upstream. Explanation from Martin Wilck:
10
11"Unfortunately, while the patch got generally positive review, it hasn't been
12finally accepted. Upstream wanted to see a solution for all affected
13architectures (in particular, also i386) which was more than we were able to do
14at the time, given that the pressure had been reduced by finding a BIOS fix."
15
16Acked-by: Jean Delvare <jdelvare@suse.de>
17
18---
19 arch/x86/kernel/apic_64.c | 39 +++++++++++++++++++++++++++++++++------
20 1 file changed, 33 insertions(+), 6 deletions(-)
21
22--- a/arch/x86/kernel/apic_64.c
23+++ b/arch/x86/kernel/apic_64.c
24@@ -299,6 +299,31 @@ static void setup_APIC_timer(void)
25 }
26
27 /*
28+ * Helper function for calibrate_APIC_clock(): Make sure that
29+ * APIC TMCTT and TSC are read at the same time, to reasonable
30+ * accuracy. On any sane system, the retry loop won't need more
31+ * than a single retry, given that the rdtsc/apic_read/rdtsc
32+ * sequence won't take more than a few cycles.
33+ */
34+
35+#define MAX_DIFFERENCE 1000UL
36+#define MAX_ITER 10
37+static inline int
38+__read_tsc_and_apic(unsigned long *tsc, unsigned *apic)
39+{
40+ unsigned long tsc0, tsc1, diff;
41+ int i = 0;
42+ do {
43+ rdtscll(tsc0);
44+ *apic = apic_read(APIC_TMCCT);
45+ rdtscll(tsc1);
46+ diff = tsc1 - tsc0;
47+ } while (diff > MAX_DIFFERENCE && ++i < MAX_ITER);
48+ *tsc = tsc0 + (diff >> 1);
49+ return diff > MAX_DIFFERENCE ? -EIO : 0;
50+}
51+
52+/*
53 * In this function we calibrate APIC bus clocks to the external
54 * timer. Unfortunately we cannot use jiffies and the timer irq
55 * to calibrate, since some later bootup code depends on getting
56@@ -317,7 +342,7 @@ static int __init calibrate_APIC_clock(v
57 {
58 unsigned apic, apic_start;
59 unsigned long tsc, tsc_start;
60- int result;
61+ int result, err_start, err;
62
63 local_irq_disable();
64
65@@ -328,25 +353,27 @@ static int __init calibrate_APIC_clock(v
66 *
67 * No interrupt enable !
68 */
69- __setup_APIC_LVTT(250000000, 0, 0);
70+ __setup_APIC_LVTT(0xffffffff, 0, 0);
71
72- apic_start = apic_read(APIC_TMCCT);
73 #ifdef CONFIG_X86_PM_TIMER
74 if (apic_calibrate_pmtmr && pmtmr_ioport) {
75+ apic_start = apic_read(APIC_TMCCT);
76 pmtimer_wait(5000); /* 5ms wait */
77 apic = apic_read(APIC_TMCCT);
78 result = (apic_start - apic) * 1000L / 5;
79 } else
80 #endif
81 {
82- rdtscll(tsc_start);
83+ err_start = __read_tsc_and_apic(&tsc_start, &apic_start);
84
85 do {
86- apic = apic_read(APIC_TMCCT);
87- rdtscll(tsc);
88+ err = __read_tsc_and_apic(&tsc, &apic);
89 } while ((tsc - tsc_start) < TICK_COUNT &&
90 (apic_start - apic) < TICK_COUNT);
91
92+ if (err_start || err)
93+ printk(KERN_CRIT "calibrate_APIC_clock: SMI flood - "
94+ "the APIC timer calibration may be wrong!\n");
95 result = (apic_start - apic) * 1000L * tsc_khz /
96 (tsc - tsc_start);
97 }