]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blob - src/patches/suse-2.6.27.39/patches.arch/x86_64_make_calibrate_APIC_clock_SMI-safe.diff
Fix oinkmaster patch.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.arch / x86_64_make_calibrate_APIC_clock_SMI-safe.diff
1 From: Martin Wilck <martin.wilck@fujitsu-siemens.com>
2 Subject: x86-64: Make APIC timer calibration SMI-safe
3 References: bnc#410452, bnc#535947
4
5 APIC timer calibration can be adversely affected if SMI are
6 triggered during calibration. Make the calibration algorithm
7 more robust to detect and workaround this situation.
8
9 This patch isn't upstream. Explanation from Martin Wilck:
10
11 "Unfortunately, while the patch got generally positive review, it hasn't been
12 finally accepted. Upstream wanted to see a solution for all affected
13 architectures (in particular, also i386) which was more than we were able to do
14 at the time, given that the pressure had been reduced by finding a BIOS fix."
15
16 Acked-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 }