diff options
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r-- | arch/x86/kernel/Makefile | 1 | ||||
-rw-r--r-- | arch/x86/kernel/amd_nb.c | 31 | ||||
-rw-r--r-- | arch/x86/kernel/asm-offsets.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/e820.c | 59 | ||||
-rw-r--r-- | arch/x86/kernel/early_printk.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/irq_32.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/irq_64.c | 35 | ||||
-rw-r--r-- | arch/x86/kernel/nmi_selftest.c | 180 | ||||
-rw-r--r-- | arch/x86/kernel/setup.c | 7 | ||||
-rw-r--r-- | arch/x86/kernel/smp.c | 72 | ||||
-rw-r--r-- | arch/x86/kernel/smpboot.c | 17 | ||||
-rw-r--r-- | arch/x86/kernel/tsc.c | 20 | ||||
-rw-r--r-- | arch/x86/kernel/x86_init.c | 1 |
13 files changed, 377 insertions, 55 deletions
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 8baca3c4871c..02b2f05b371e 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile | |||
@@ -80,6 +80,7 @@ obj-$(CONFIG_APB_TIMER) += apb_timer.o | |||
80 | obj-$(CONFIG_AMD_NB) += amd_nb.o | 80 | obj-$(CONFIG_AMD_NB) += amd_nb.o |
81 | obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o | 81 | obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o |
82 | obj-$(CONFIG_DEBUG_NX_TEST) += test_nx.o | 82 | obj-$(CONFIG_DEBUG_NX_TEST) += test_nx.o |
83 | obj-$(CONFIG_DEBUG_NMI_SELFTEST) += nmi_selftest.o | ||
83 | 84 | ||
84 | obj-$(CONFIG_KVM_GUEST) += kvm.o | 85 | obj-$(CONFIG_KVM_GUEST) += kvm.o |
85 | obj-$(CONFIG_KVM_CLOCK) += kvmclock.o | 86 | obj-$(CONFIG_KVM_CLOCK) += kvmclock.o |
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 013c1810ce72..be16854591cc 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c | |||
@@ -119,6 +119,37 @@ bool __init early_is_amd_nb(u32 device) | |||
119 | return false; | 119 | return false; |
120 | } | 120 | } |
121 | 121 | ||
122 | struct resource *amd_get_mmconfig_range(struct resource *res) | ||
123 | { | ||
124 | u32 address; | ||
125 | u64 base, msr; | ||
126 | unsigned segn_busn_bits; | ||
127 | |||
128 | if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) | ||
129 | return NULL; | ||
130 | |||
131 | /* assume all cpus from fam10h have mmconfig */ | ||
132 | if (boot_cpu_data.x86 < 0x10) | ||
133 | return NULL; | ||
134 | |||
135 | address = MSR_FAM10H_MMIO_CONF_BASE; | ||
136 | rdmsrl(address, msr); | ||
137 | |||
138 | /* mmconfig is not enabled */ | ||
139 | if (!(msr & FAM10H_MMIO_CONF_ENABLE)) | ||
140 | return NULL; | ||
141 | |||
142 | base = msr & (FAM10H_MMIO_CONF_BASE_MASK<<FAM10H_MMIO_CONF_BASE_SHIFT); | ||
143 | |||
144 | segn_busn_bits = (msr >> FAM10H_MMIO_CONF_BUSRANGE_SHIFT) & | ||
145 | FAM10H_MMIO_CONF_BUSRANGE_MASK; | ||
146 | |||
147 | res->flags = IORESOURCE_MEM; | ||
148 | res->start = base; | ||
149 | res->end = base + (1ULL<<(segn_busn_bits + 20)) - 1; | ||
150 | return res; | ||
151 | } | ||
152 | |||
122 | int amd_get_subcaches(int cpu) | 153 | int amd_get_subcaches(int cpu) |
123 | { | 154 | { |
124 | struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link; | 155 | struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link; |
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c index 4f13fafc5264..68de2dc962ec 100644 --- a/arch/x86/kernel/asm-offsets.c +++ b/arch/x86/kernel/asm-offsets.c | |||
@@ -67,4 +67,6 @@ void common(void) { | |||
67 | OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch); | 67 | OFFSET(BP_hardware_subarch, boot_params, hdr.hardware_subarch); |
68 | OFFSET(BP_version, boot_params, hdr.version); | 68 | OFFSET(BP_version, boot_params, hdr.version); |
69 | OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment); | 69 | OFFSET(BP_kernel_alignment, boot_params, hdr.kernel_alignment); |
70 | OFFSET(BP_pref_address, boot_params, hdr.pref_address); | ||
71 | OFFSET(BP_code32_start, boot_params, hdr.code32_start); | ||
70 | } | 72 | } |
diff --git a/arch/x86/kernel/e820.c b/arch/x86/kernel/e820.c index 8071e2f3d6eb..174d938d576b 100644 --- a/arch/x86/kernel/e820.c +++ b/arch/x86/kernel/e820.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/acpi.h> | 19 | #include <linux/acpi.h> |
20 | #include <linux/firmware-map.h> | 20 | #include <linux/firmware-map.h> |
21 | #include <linux/memblock.h> | 21 | #include <linux/memblock.h> |
22 | #include <linux/sort.h> | ||
22 | 23 | ||
23 | #include <asm/e820.h> | 24 | #include <asm/e820.h> |
24 | #include <asm/proto.h> | 25 | #include <asm/proto.h> |
@@ -227,22 +228,38 @@ void __init e820_print_map(char *who) | |||
227 | * ____________________33__ | 228 | * ____________________33__ |
228 | * ______________________4_ | 229 | * ______________________4_ |
229 | */ | 230 | */ |
231 | struct change_member { | ||
232 | struct e820entry *pbios; /* pointer to original bios entry */ | ||
233 | unsigned long long addr; /* address for this change point */ | ||
234 | }; | ||
235 | |||
236 | static int __init cpcompare(const void *a, const void *b) | ||
237 | { | ||
238 | struct change_member * const *app = a, * const *bpp = b; | ||
239 | const struct change_member *ap = *app, *bp = *bpp; | ||
240 | |||
241 | /* | ||
242 | * Inputs are pointers to two elements of change_point[]. If their | ||
243 | * addresses are unequal, their difference dominates. If the addresses | ||
244 | * are equal, then consider one that represents the end of its region | ||
245 | * to be greater than one that does not. | ||
246 | */ | ||
247 | if (ap->addr != bp->addr) | ||
248 | return ap->addr > bp->addr ? 1 : -1; | ||
249 | |||
250 | return (ap->addr != ap->pbios->addr) - (bp->addr != bp->pbios->addr); | ||
251 | } | ||
230 | 252 | ||
231 | int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, | 253 | int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, |
232 | u32 *pnr_map) | 254 | u32 *pnr_map) |
233 | { | 255 | { |
234 | struct change_member { | ||
235 | struct e820entry *pbios; /* pointer to original bios entry */ | ||
236 | unsigned long long addr; /* address for this change point */ | ||
237 | }; | ||
238 | static struct change_member change_point_list[2*E820_X_MAX] __initdata; | 256 | static struct change_member change_point_list[2*E820_X_MAX] __initdata; |
239 | static struct change_member *change_point[2*E820_X_MAX] __initdata; | 257 | static struct change_member *change_point[2*E820_X_MAX] __initdata; |
240 | static struct e820entry *overlap_list[E820_X_MAX] __initdata; | 258 | static struct e820entry *overlap_list[E820_X_MAX] __initdata; |
241 | static struct e820entry new_bios[E820_X_MAX] __initdata; | 259 | static struct e820entry new_bios[E820_X_MAX] __initdata; |
242 | struct change_member *change_tmp; | ||
243 | unsigned long current_type, last_type; | 260 | unsigned long current_type, last_type; |
244 | unsigned long long last_addr; | 261 | unsigned long long last_addr; |
245 | int chgidx, still_changing; | 262 | int chgidx; |
246 | int overlap_entries; | 263 | int overlap_entries; |
247 | int new_bios_entry; | 264 | int new_bios_entry; |
248 | int old_nr, new_nr, chg_nr; | 265 | int old_nr, new_nr, chg_nr; |
@@ -279,35 +296,7 @@ int __init sanitize_e820_map(struct e820entry *biosmap, int max_nr_map, | |||
279 | chg_nr = chgidx; | 296 | chg_nr = chgidx; |
280 | 297 | ||
281 | /* sort change-point list by memory addresses (low -> high) */ | 298 | /* sort change-point list by memory addresses (low -> high) */ |
282 | still_changing = 1; | 299 | sort(change_point, chg_nr, sizeof *change_point, cpcompare, NULL); |
283 | while (still_changing) { | ||
284 | still_changing = 0; | ||
285 | for (i = 1; i < chg_nr; i++) { | ||
286 | unsigned long long curaddr, lastaddr; | ||
287 | unsigned long long curpbaddr, lastpbaddr; | ||
288 | |||
289 | curaddr = change_point[i]->addr; | ||
290 | lastaddr = change_point[i - 1]->addr; | ||
291 | curpbaddr = change_point[i]->pbios->addr; | ||
292 | lastpbaddr = change_point[i - 1]->pbios->addr; | ||
293 | |||
294 | /* | ||
295 | * swap entries, when: | ||
296 | * | ||
297 | * curaddr > lastaddr or | ||
298 | * curaddr == lastaddr and curaddr == curpbaddr and | ||
299 | * lastaddr != lastpbaddr | ||
300 | */ | ||
301 | if (curaddr < lastaddr || | ||
302 | (curaddr == lastaddr && curaddr == curpbaddr && | ||
303 | lastaddr != lastpbaddr)) { | ||
304 | change_tmp = change_point[i]; | ||
305 | change_point[i] = change_point[i-1]; | ||
306 | change_point[i-1] = change_tmp; | ||
307 | still_changing = 1; | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | 300 | ||
312 | /* create a new bios memory map, removing overlaps */ | 301 | /* create a new bios memory map, removing overlaps */ |
313 | overlap_entries = 0; /* number of entries in the overlap table */ | 302 | overlap_entries = 0; /* number of entries in the overlap table */ |
diff --git a/arch/x86/kernel/early_printk.c b/arch/x86/kernel/early_printk.c index 9d42a52d2331..9b9f18b49918 100644 --- a/arch/x86/kernel/early_printk.c +++ b/arch/x86/kernel/early_printk.c | |||
@@ -240,7 +240,7 @@ static int __init setup_early_printk(char *buf) | |||
240 | if (!strncmp(buf, "xen", 3)) | 240 | if (!strncmp(buf, "xen", 3)) |
241 | early_console_register(&xenboot_console, keep); | 241 | early_console_register(&xenboot_console, keep); |
242 | #endif | 242 | #endif |
243 | #ifdef CONFIG_EARLY_PRINTK_MRST | 243 | #ifdef CONFIG_EARLY_PRINTK_INTEL_MID |
244 | if (!strncmp(buf, "mrst", 4)) { | 244 | if (!strncmp(buf, "mrst", 4)) { |
245 | mrst_early_console_init(); | 245 | mrst_early_console_init(); |
246 | early_console_register(&early_mrst_console, keep); | 246 | early_console_register(&early_mrst_console, keep); |
diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index 72090705a656..40fc86161d92 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c | |||
@@ -28,6 +28,9 @@ DEFINE_PER_CPU(struct pt_regs *, irq_regs); | |||
28 | EXPORT_PER_CPU_SYMBOL(irq_regs); | 28 | EXPORT_PER_CPU_SYMBOL(irq_regs); |
29 | 29 | ||
30 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | 30 | #ifdef CONFIG_DEBUG_STACKOVERFLOW |
31 | |||
32 | int sysctl_panic_on_stackoverflow __read_mostly; | ||
33 | |||
31 | /* Debugging check for stack overflow: is there less than 1KB free? */ | 34 | /* Debugging check for stack overflow: is there less than 1KB free? */ |
32 | static int check_stack_overflow(void) | 35 | static int check_stack_overflow(void) |
33 | { | 36 | { |
@@ -43,6 +46,8 @@ static void print_stack_overflow(void) | |||
43 | { | 46 | { |
44 | printk(KERN_WARNING "low stack detected by irq handler\n"); | 47 | printk(KERN_WARNING "low stack detected by irq handler\n"); |
45 | dump_stack(); | 48 | dump_stack(); |
49 | if (sysctl_panic_on_stackoverflow) | ||
50 | panic("low stack detected by irq handler - check messages\n"); | ||
46 | } | 51 | } |
47 | 52 | ||
48 | #else | 53 | #else |
diff --git a/arch/x86/kernel/irq_64.c b/arch/x86/kernel/irq_64.c index 69bca468c47a..d04d3ecded62 100644 --- a/arch/x86/kernel/irq_64.c +++ b/arch/x86/kernel/irq_64.c | |||
@@ -26,6 +26,8 @@ EXPORT_PER_CPU_SYMBOL(irq_stat); | |||
26 | DEFINE_PER_CPU(struct pt_regs *, irq_regs); | 26 | DEFINE_PER_CPU(struct pt_regs *, irq_regs); |
27 | EXPORT_PER_CPU_SYMBOL(irq_regs); | 27 | EXPORT_PER_CPU_SYMBOL(irq_regs); |
28 | 28 | ||
29 | int sysctl_panic_on_stackoverflow; | ||
30 | |||
29 | /* | 31 | /* |
30 | * Probabilistic stack overflow check: | 32 | * Probabilistic stack overflow check: |
31 | * | 33 | * |
@@ -36,18 +38,39 @@ EXPORT_PER_CPU_SYMBOL(irq_regs); | |||
36 | static inline void stack_overflow_check(struct pt_regs *regs) | 38 | static inline void stack_overflow_check(struct pt_regs *regs) |
37 | { | 39 | { |
38 | #ifdef CONFIG_DEBUG_STACKOVERFLOW | 40 | #ifdef CONFIG_DEBUG_STACKOVERFLOW |
41 | #define STACK_TOP_MARGIN 128 | ||
42 | struct orig_ist *oist; | ||
43 | u64 irq_stack_top, irq_stack_bottom; | ||
44 | u64 estack_top, estack_bottom; | ||
39 | u64 curbase = (u64)task_stack_page(current); | 45 | u64 curbase = (u64)task_stack_page(current); |
40 | 46 | ||
41 | if (user_mode_vm(regs)) | 47 | if (user_mode_vm(regs)) |
42 | return; | 48 | return; |
43 | 49 | ||
44 | WARN_ONCE(regs->sp >= curbase && | 50 | if (regs->sp >= curbase + sizeof(struct thread_info) + |
45 | regs->sp <= curbase + THREAD_SIZE && | 51 | sizeof(struct pt_regs) + STACK_TOP_MARGIN && |
46 | regs->sp < curbase + sizeof(struct thread_info) + | 52 | regs->sp <= curbase + THREAD_SIZE) |
47 | sizeof(struct pt_regs) + 128, | 53 | return; |
54 | |||
55 | irq_stack_top = (u64)__get_cpu_var(irq_stack_union.irq_stack) + | ||
56 | STACK_TOP_MARGIN; | ||
57 | irq_stack_bottom = (u64)__get_cpu_var(irq_stack_ptr); | ||
58 | if (regs->sp >= irq_stack_top && regs->sp <= irq_stack_bottom) | ||
59 | return; | ||
60 | |||
61 | oist = &__get_cpu_var(orig_ist); | ||
62 | estack_top = (u64)oist->ist[0] - EXCEPTION_STKSZ + STACK_TOP_MARGIN; | ||
63 | estack_bottom = (u64)oist->ist[N_EXCEPTION_STACKS - 1]; | ||
64 | if (regs->sp >= estack_top && regs->sp <= estack_bottom) | ||
65 | return; | ||
66 | |||
67 | WARN_ONCE(1, "do_IRQ(): %s has overflown the kernel stack (cur:%Lx,sp:%lx,irq stk top-bottom:%Lx-%Lx,exception stk top-bottom:%Lx-%Lx)\n", | ||
68 | current->comm, curbase, regs->sp, | ||
69 | irq_stack_top, irq_stack_bottom, | ||
70 | estack_top, estack_bottom); | ||
48 | 71 | ||
49 | "do_IRQ: %s near stack overflow (cur:%Lx,sp:%lx)\n", | 72 | if (sysctl_panic_on_stackoverflow) |
50 | current->comm, curbase, regs->sp); | 73 | panic("low stack detected by irq handler - check messages\n"); |
51 | #endif | 74 | #endif |
52 | } | 75 | } |
53 | 76 | ||
diff --git a/arch/x86/kernel/nmi_selftest.c b/arch/x86/kernel/nmi_selftest.c new file mode 100644 index 000000000000..0d01a8ea4e11 --- /dev/null +++ b/arch/x86/kernel/nmi_selftest.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * arch/x86/kernel/nmi-selftest.c | ||
3 | * | ||
4 | * Testsuite for NMI: IPIs | ||
5 | * | ||
6 | * Started by Don Zickus: | ||
7 | * (using lib/locking-selftest.c as a guide) | ||
8 | * | ||
9 | * Copyright (C) 2011 Red Hat, Inc., Don Zickus <dzickus@redhat.com> | ||
10 | */ | ||
11 | |||
12 | #include <linux/smp.h> | ||
13 | #include <linux/cpumask.h> | ||
14 | #include <linux/delay.h> | ||
15 | |||
16 | #include <asm/apic.h> | ||
17 | #include <asm/nmi.h> | ||
18 | |||
19 | #define SUCCESS 0 | ||
20 | #define FAILURE 1 | ||
21 | #define TIMEOUT 2 | ||
22 | |||
23 | static int nmi_fail; | ||
24 | |||
25 | /* check to see if NMI IPIs work on this machine */ | ||
26 | static DECLARE_BITMAP(nmi_ipi_mask, NR_CPUS) __read_mostly; | ||
27 | |||
28 | static int testcase_total; | ||
29 | static int testcase_successes; | ||
30 | static int expected_testcase_failures; | ||
31 | static int unexpected_testcase_failures; | ||
32 | static int unexpected_testcase_unknowns; | ||
33 | |||
34 | static int nmi_unk_cb(unsigned int val, struct pt_regs *regs) | ||
35 | { | ||
36 | unexpected_testcase_unknowns++; | ||
37 | return NMI_HANDLED; | ||
38 | } | ||
39 | |||
40 | static void init_nmi_testsuite(void) | ||
41 | { | ||
42 | /* trap all the unknown NMIs we may generate */ | ||
43 | register_nmi_handler(NMI_UNKNOWN, nmi_unk_cb, 0, "nmi_selftest_unk"); | ||
44 | } | ||
45 | |||
46 | static void cleanup_nmi_testsuite(void) | ||
47 | { | ||
48 | unregister_nmi_handler(NMI_UNKNOWN, "nmi_selftest_unk"); | ||
49 | } | ||
50 | |||
51 | static int test_nmi_ipi_callback(unsigned int val, struct pt_regs *regs) | ||
52 | { | ||
53 | int cpu = raw_smp_processor_id(); | ||
54 | |||
55 | if (cpumask_test_and_clear_cpu(cpu, to_cpumask(nmi_ipi_mask))) | ||
56 | return NMI_HANDLED; | ||
57 | |||
58 | return NMI_DONE; | ||
59 | } | ||
60 | |||
61 | static void test_nmi_ipi(struct cpumask *mask) | ||
62 | { | ||
63 | unsigned long timeout; | ||
64 | |||
65 | if (register_nmi_handler(NMI_LOCAL, test_nmi_ipi_callback, | ||
66 | NMI_FLAG_FIRST, "nmi_selftest")) { | ||
67 | nmi_fail = FAILURE; | ||
68 | return; | ||
69 | } | ||
70 | |||
71 | /* sync above data before sending NMI */ | ||
72 | wmb(); | ||
73 | |||
74 | apic->send_IPI_mask(mask, NMI_VECTOR); | ||
75 | |||
76 | /* Don't wait longer than a second */ | ||
77 | timeout = USEC_PER_SEC; | ||
78 | while (!cpumask_empty(mask) && timeout--) | ||
79 | udelay(1); | ||
80 | |||
81 | /* What happens if we timeout, do we still unregister?? */ | ||
82 | unregister_nmi_handler(NMI_LOCAL, "nmi_selftest"); | ||
83 | |||
84 | if (!timeout) | ||
85 | nmi_fail = TIMEOUT; | ||
86 | return; | ||
87 | } | ||
88 | |||
89 | static void remote_ipi(void) | ||
90 | { | ||
91 | cpumask_copy(to_cpumask(nmi_ipi_mask), cpu_online_mask); | ||
92 | cpumask_clear_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask)); | ||
93 | if (!cpumask_empty(to_cpumask(nmi_ipi_mask))) | ||
94 | test_nmi_ipi(to_cpumask(nmi_ipi_mask)); | ||
95 | } | ||
96 | |||
97 | static void local_ipi(void) | ||
98 | { | ||
99 | cpumask_clear(to_cpumask(nmi_ipi_mask)); | ||
100 | cpumask_set_cpu(smp_processor_id(), to_cpumask(nmi_ipi_mask)); | ||
101 | test_nmi_ipi(to_cpumask(nmi_ipi_mask)); | ||
102 | } | ||
103 | |||
104 | static void reset_nmi(void) | ||
105 | { | ||
106 | nmi_fail = 0; | ||
107 | } | ||
108 | |||
109 | static void dotest(void (*testcase_fn)(void), int expected) | ||
110 | { | ||
111 | testcase_fn(); | ||
112 | /* | ||
113 | * Filter out expected failures: | ||
114 | */ | ||
115 | if (nmi_fail != expected) { | ||
116 | unexpected_testcase_failures++; | ||
117 | |||
118 | if (nmi_fail == FAILURE) | ||
119 | printk("FAILED |"); | ||
120 | else if (nmi_fail == TIMEOUT) | ||
121 | printk("TIMEOUT|"); | ||
122 | else | ||
123 | printk("ERROR |"); | ||
124 | dump_stack(); | ||
125 | } else { | ||
126 | testcase_successes++; | ||
127 | printk(" ok |"); | ||
128 | } | ||
129 | testcase_total++; | ||
130 | |||
131 | reset_nmi(); | ||
132 | } | ||
133 | |||
134 | static inline void print_testname(const char *testname) | ||
135 | { | ||
136 | printk("%12s:", testname); | ||
137 | } | ||
138 | |||
139 | void nmi_selftest(void) | ||
140 | { | ||
141 | init_nmi_testsuite(); | ||
142 | |||
143 | /* | ||
144 | * Run the testsuite: | ||
145 | */ | ||
146 | printk("----------------\n"); | ||
147 | printk("| NMI testsuite:\n"); | ||
148 | printk("--------------------\n"); | ||
149 | |||
150 | print_testname("remote IPI"); | ||
151 | dotest(remote_ipi, SUCCESS); | ||
152 | printk("\n"); | ||
153 | print_testname("local IPI"); | ||
154 | dotest(local_ipi, SUCCESS); | ||
155 | printk("\n"); | ||
156 | |||
157 | cleanup_nmi_testsuite(); | ||
158 | |||
159 | if (unexpected_testcase_failures) { | ||
160 | printk("--------------------\n"); | ||
161 | printk("BUG: %3d unexpected failures (out of %3d) - debugging disabled! |\n", | ||
162 | unexpected_testcase_failures, testcase_total); | ||
163 | printk("-----------------------------------------------------------------\n"); | ||
164 | } else if (expected_testcase_failures && testcase_successes) { | ||
165 | printk("--------------------\n"); | ||
166 | printk("%3d out of %3d testcases failed, as expected. |\n", | ||
167 | expected_testcase_failures, testcase_total); | ||
168 | printk("----------------------------------------------------\n"); | ||
169 | } else if (expected_testcase_failures && !testcase_successes) { | ||
170 | printk("--------------------\n"); | ||
171 | printk("All %3d testcases failed, as expected. |\n", | ||
172 | expected_testcase_failures); | ||
173 | printk("----------------------------------------\n"); | ||
174 | } else { | ||
175 | printk("--------------------\n"); | ||
176 | printk("Good, all %3d testcases passed! |\n", | ||
177 | testcase_successes); | ||
178 | printk("---------------------------------\n"); | ||
179 | } | ||
180 | } | ||
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index d05444ac2aea..d7d5099fe874 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c | |||
@@ -749,12 +749,7 @@ void __init setup_arch(char **cmdline_p) | |||
749 | #endif | 749 | #endif |
750 | #ifdef CONFIG_EFI | 750 | #ifdef CONFIG_EFI |
751 | if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, | 751 | if (!strncmp((char *)&boot_params.efi_info.efi_loader_signature, |
752 | #ifdef CONFIG_X86_32 | 752 | EFI_LOADER_SIGNATURE, 4)) { |
753 | "EL32", | ||
754 | #else | ||
755 | "EL64", | ||
756 | #endif | ||
757 | 4)) { | ||
758 | efi_enabled = 1; | 753 | efi_enabled = 1; |
759 | efi_memblock_x86_reserve_range(); | 754 | efi_memblock_x86_reserve_range(); |
760 | } | 755 | } |
diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index 16204dc15484..66c74f481cab 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <asm/mmu_context.h> | 29 | #include <asm/mmu_context.h> |
30 | #include <asm/proto.h> | 30 | #include <asm/proto.h> |
31 | #include <asm/apic.h> | 31 | #include <asm/apic.h> |
32 | #include <asm/nmi.h> | ||
32 | /* | 33 | /* |
33 | * Some notes on x86 processor bugs affecting SMP operation: | 34 | * Some notes on x86 processor bugs affecting SMP operation: |
34 | * | 35 | * |
@@ -148,6 +149,60 @@ void native_send_call_func_ipi(const struct cpumask *mask) | |||
148 | free_cpumask_var(allbutself); | 149 | free_cpumask_var(allbutself); |
149 | } | 150 | } |
150 | 151 | ||
152 | static atomic_t stopping_cpu = ATOMIC_INIT(-1); | ||
153 | |||
154 | static int smp_stop_nmi_callback(unsigned int val, struct pt_regs *regs) | ||
155 | { | ||
156 | /* We are registered on stopping cpu too, avoid spurious NMI */ | ||
157 | if (raw_smp_processor_id() == atomic_read(&stopping_cpu)) | ||
158 | return NMI_HANDLED; | ||
159 | |||
160 | stop_this_cpu(NULL); | ||
161 | |||
162 | return NMI_HANDLED; | ||
163 | } | ||
164 | |||
165 | static void native_nmi_stop_other_cpus(int wait) | ||
166 | { | ||
167 | unsigned long flags; | ||
168 | unsigned long timeout; | ||
169 | |||
170 | if (reboot_force) | ||
171 | return; | ||
172 | |||
173 | /* | ||
174 | * Use an own vector here because smp_call_function | ||
175 | * does lots of things not suitable in a panic situation. | ||
176 | */ | ||
177 | if (num_online_cpus() > 1) { | ||
178 | /* did someone beat us here? */ | ||
179 | if (atomic_cmpxchg(&stopping_cpu, -1, safe_smp_processor_id()) != -1) | ||
180 | return; | ||
181 | |||
182 | if (register_nmi_handler(NMI_LOCAL, smp_stop_nmi_callback, | ||
183 | NMI_FLAG_FIRST, "smp_stop")) | ||
184 | /* Note: we ignore failures here */ | ||
185 | return; | ||
186 | |||
187 | /* sync above data before sending NMI */ | ||
188 | wmb(); | ||
189 | |||
190 | apic->send_IPI_allbutself(NMI_VECTOR); | ||
191 | |||
192 | /* | ||
193 | * Don't wait longer than a second if the caller | ||
194 | * didn't ask us to wait. | ||
195 | */ | ||
196 | timeout = USEC_PER_SEC; | ||
197 | while (num_online_cpus() > 1 && (wait || timeout--)) | ||
198 | udelay(1); | ||
199 | } | ||
200 | |||
201 | local_irq_save(flags); | ||
202 | disable_local_APIC(); | ||
203 | local_irq_restore(flags); | ||
204 | } | ||
205 | |||
151 | /* | 206 | /* |
152 | * this function calls the 'stop' function on all other CPUs in the system. | 207 | * this function calls the 'stop' function on all other CPUs in the system. |
153 | */ | 208 | */ |
@@ -160,7 +215,7 @@ asmlinkage void smp_reboot_interrupt(void) | |||
160 | irq_exit(); | 215 | irq_exit(); |
161 | } | 216 | } |
162 | 217 | ||
163 | static void native_stop_other_cpus(int wait) | 218 | static void native_irq_stop_other_cpus(int wait) |
164 | { | 219 | { |
165 | unsigned long flags; | 220 | unsigned long flags; |
166 | unsigned long timeout; | 221 | unsigned long timeout; |
@@ -194,6 +249,11 @@ static void native_stop_other_cpus(int wait) | |||
194 | local_irq_restore(flags); | 249 | local_irq_restore(flags); |
195 | } | 250 | } |
196 | 251 | ||
252 | static void native_smp_disable_nmi_ipi(void) | ||
253 | { | ||
254 | smp_ops.stop_other_cpus = native_irq_stop_other_cpus; | ||
255 | } | ||
256 | |||
197 | /* | 257 | /* |
198 | * Reschedule call back. | 258 | * Reschedule call back. |
199 | */ | 259 | */ |
@@ -225,12 +285,20 @@ void smp_call_function_single_interrupt(struct pt_regs *regs) | |||
225 | irq_exit(); | 285 | irq_exit(); |
226 | } | 286 | } |
227 | 287 | ||
288 | static int __init nonmi_ipi_setup(char *str) | ||
289 | { | ||
290 | native_smp_disable_nmi_ipi(); | ||
291 | return 1; | ||
292 | } | ||
293 | |||
294 | __setup("nonmi_ipi", nonmi_ipi_setup); | ||
295 | |||
228 | struct smp_ops smp_ops = { | 296 | struct smp_ops smp_ops = { |
229 | .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu, | 297 | .smp_prepare_boot_cpu = native_smp_prepare_boot_cpu, |
230 | .smp_prepare_cpus = native_smp_prepare_cpus, | 298 | .smp_prepare_cpus = native_smp_prepare_cpus, |
231 | .smp_cpus_done = native_smp_cpus_done, | 299 | .smp_cpus_done = native_smp_cpus_done, |
232 | 300 | ||
233 | .stop_other_cpus = native_stop_other_cpus, | 301 | .stop_other_cpus = native_nmi_stop_other_cpus, |
234 | .smp_send_reschedule = native_smp_send_reschedule, | 302 | .smp_send_reschedule = native_smp_send_reschedule, |
235 | 303 | ||
236 | .cpu_up = native_cpu_up, | 304 | .cpu_up = native_cpu_up, |
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index e38e21754eea..66d250c00d11 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -207,23 +207,29 @@ static void __cpuinit smp_callin(void) | |||
207 | * Need to setup vector mappings before we enable interrupts. | 207 | * Need to setup vector mappings before we enable interrupts. |
208 | */ | 208 | */ |
209 | setup_vector_irq(smp_processor_id()); | 209 | setup_vector_irq(smp_processor_id()); |
210 | |||
211 | /* | ||
212 | * Save our processor parameters. Note: this information | ||
213 | * is needed for clock calibration. | ||
214 | */ | ||
215 | smp_store_cpu_info(cpuid); | ||
216 | |||
210 | /* | 217 | /* |
211 | * Get our bogomips. | 218 | * Get our bogomips. |
219 | * Update loops_per_jiffy in cpu_data. Previous call to | ||
220 | * smp_store_cpu_info() stored a value that is close but not as | ||
221 | * accurate as the value just calculated. | ||
212 | * | 222 | * |
213 | * Need to enable IRQs because it can take longer and then | 223 | * Need to enable IRQs because it can take longer and then |
214 | * the NMI watchdog might kill us. | 224 | * the NMI watchdog might kill us. |
215 | */ | 225 | */ |
216 | local_irq_enable(); | 226 | local_irq_enable(); |
217 | calibrate_delay(); | 227 | calibrate_delay(); |
228 | cpu_data(cpuid).loops_per_jiffy = loops_per_jiffy; | ||
218 | local_irq_disable(); | 229 | local_irq_disable(); |
219 | pr_debug("Stack at about %p\n", &cpuid); | 230 | pr_debug("Stack at about %p\n", &cpuid); |
220 | 231 | ||
221 | /* | 232 | /* |
222 | * Save our processor parameters | ||
223 | */ | ||
224 | smp_store_cpu_info(cpuid); | ||
225 | |||
226 | /* | ||
227 | * This must be done before setting cpu_online_mask | 233 | * This must be done before setting cpu_online_mask |
228 | * or calling notify_cpu_starting. | 234 | * or calling notify_cpu_starting. |
229 | */ | 235 | */ |
@@ -1143,6 +1149,7 @@ void __init native_smp_cpus_done(unsigned int max_cpus) | |||
1143 | { | 1149 | { |
1144 | pr_debug("Boot done.\n"); | 1150 | pr_debug("Boot done.\n"); |
1145 | 1151 | ||
1152 | nmi_selftest(); | ||
1146 | impress_friends(); | 1153 | impress_friends(); |
1147 | #ifdef CONFIG_X86_IO_APIC | 1154 | #ifdef CONFIG_X86_IO_APIC |
1148 | setup_ioapic_dest(); | 1155 | setup_ioapic_dest(); |
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 2c9cf0fd78f5..c0dd5b603749 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
@@ -995,3 +995,23 @@ void __init tsc_init(void) | |||
995 | check_system_tsc_reliable(); | 995 | check_system_tsc_reliable(); |
996 | } | 996 | } |
997 | 997 | ||
998 | #ifdef CONFIG_SMP | ||
999 | /* | ||
1000 | * If we have a constant TSC and are using the TSC for the delay loop, | ||
1001 | * we can skip clock calibration if another cpu in the same socket has already | ||
1002 | * been calibrated. This assumes that CONSTANT_TSC applies to all | ||
1003 | * cpus in the socket - this should be a safe assumption. | ||
1004 | */ | ||
1005 | unsigned long __cpuinit calibrate_delay_is_known(void) | ||
1006 | { | ||
1007 | int i, cpu = smp_processor_id(); | ||
1008 | |||
1009 | if (!tsc_disabled && !cpu_has(&cpu_data(cpu), X86_FEATURE_CONSTANT_TSC)) | ||
1010 | return 0; | ||
1011 | |||
1012 | for_each_online_cpu(i) | ||
1013 | if (cpu_data(i).phys_proc_id == cpu_data(cpu).phys_proc_id) | ||
1014 | return cpu_data(i).loops_per_jiffy; | ||
1015 | return 0; | ||
1016 | } | ||
1017 | #endif | ||
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c index 91f83e21b989..947a06ccc673 100644 --- a/arch/x86/kernel/x86_init.c +++ b/arch/x86/kernel/x86_init.c | |||
@@ -115,4 +115,5 @@ struct x86_msi_ops x86_msi = { | |||
115 | .setup_msi_irqs = native_setup_msi_irqs, | 115 | .setup_msi_irqs = native_setup_msi_irqs, |
116 | .teardown_msi_irq = native_teardown_msi_irq, | 116 | .teardown_msi_irq = native_teardown_msi_irq, |
117 | .teardown_msi_irqs = default_teardown_msi_irqs, | 117 | .teardown_msi_irqs = default_teardown_msi_irqs, |
118 | .restore_msi_irqs = default_restore_msi_irqs, | ||
118 | }; | 119 | }; |