diff options
author | Michael D Labriola <michael.d.labriola@gmail.com> | 2012-02-01 10:05:00 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2012-02-07 05:34:11 -0500 |
commit | 57b165948fe0e1cca78bca1fe1e1ae9a38baedd2 (patch) | |
tree | d643576c8705a70f05047b9cb3e4b564f6d8f4df /arch/x86/kernel/reboot.c | |
parent | 7915a2e902df9fdb5ea5d5786a4172b38d0ea71e (diff) |
x86/reboot: Reduce to a single DMI table for reboot quirks
This commit reduces the X86_32 reboot_dmi_table and the X86_64
pci_reboot_dmi_table into a single table with a single set of
functions (e.g., only 1 call to core_initcall).
The table entries that use set_bios_reboot are grouped together
inside a #define CONFIG_X86_32 block.
Note that there's a single entry that uses set_kbd_reboot, which
used to be available only on X86_32. This commit moves that
entry outside the X86_32 block because it seems it never should
have been in there. There's multiple places in reboot.c that
assume KBD is valid regardless of X86_32/X86_64.
Signed-off-by: Michael D Labriola <michael.d.labriola@gmail.com>
Cc: Matthew Garrett <mjg@redhat.com>
Link: http://lkml.kernel.org/n/tip-lv3aliubas2l3aenq8v3uklk@git.kernel.org
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/reboot.c')
-rw-r--r-- | arch/x86/kernel/reboot.c | 176 |
1 files changed, 83 insertions, 93 deletions
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index d840e69a853c..e73973769076 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -150,6 +150,80 @@ static int __init set_bios_reboot(const struct dmi_system_id *d) | |||
150 | return 0; | 150 | return 0; |
151 | } | 151 | } |
152 | 152 | ||
153 | extern const unsigned char machine_real_restart_asm[]; | ||
154 | extern const u64 machine_real_restart_gdt[3]; | ||
155 | |||
156 | void machine_real_restart(unsigned int type) | ||
157 | { | ||
158 | void *restart_va; | ||
159 | unsigned long restart_pa; | ||
160 | void (*restart_lowmem)(unsigned int); | ||
161 | u64 *lowmem_gdt; | ||
162 | |||
163 | local_irq_disable(); | ||
164 | |||
165 | /* Write zero to CMOS register number 0x0f, which the BIOS POST | ||
166 | routine will recognize as telling it to do a proper reboot. (Well | ||
167 | that's what this book in front of me says -- it may only apply to | ||
168 | the Phoenix BIOS though, it's not clear). At the same time, | ||
169 | disable NMIs by setting the top bit in the CMOS address register, | ||
170 | as we're about to do peculiar things to the CPU. I'm not sure if | ||
171 | `outb_p' is needed instead of just `outb'. Use it to be on the | ||
172 | safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) | ||
173 | */ | ||
174 | spin_lock(&rtc_lock); | ||
175 | CMOS_WRITE(0x00, 0x8f); | ||
176 | spin_unlock(&rtc_lock); | ||
177 | |||
178 | /* | ||
179 | * Switch back to the initial page table. | ||
180 | */ | ||
181 | load_cr3(initial_page_table); | ||
182 | |||
183 | /* Write 0x1234 to absolute memory location 0x472. The BIOS reads | ||
184 | this on booting to tell it to "Bypass memory test (also warm | ||
185 | boot)". This seems like a fairly standard thing that gets set by | ||
186 | REBOOT.COM programs, and the previous reset routine did this | ||
187 | too. */ | ||
188 | *((unsigned short *)0x472) = reboot_mode; | ||
189 | |||
190 | /* Patch the GDT in the low memory trampoline */ | ||
191 | lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt); | ||
192 | |||
193 | restart_va = TRAMPOLINE_SYM(machine_real_restart_asm); | ||
194 | restart_pa = virt_to_phys(restart_va); | ||
195 | restart_lowmem = (void (*)(unsigned int))restart_pa; | ||
196 | |||
197 | /* GDT[0]: GDT self-pointer */ | ||
198 | lowmem_gdt[0] = | ||
199 | (u64)(sizeof(machine_real_restart_gdt) - 1) + | ||
200 | ((u64)virt_to_phys(lowmem_gdt) << 16); | ||
201 | /* GDT[1]: 64K real mode code segment */ | ||
202 | lowmem_gdt[1] = | ||
203 | GDT_ENTRY(0x009b, restart_pa, 0xffff); | ||
204 | |||
205 | /* Jump to the identity-mapped low memory code */ | ||
206 | restart_lowmem(type); | ||
207 | } | ||
208 | #ifdef CONFIG_APM_MODULE | ||
209 | EXPORT_SYMBOL(machine_real_restart); | ||
210 | #endif | ||
211 | |||
212 | #endif /* CONFIG_X86_32 */ | ||
213 | |||
214 | /* | ||
215 | * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot | ||
216 | */ | ||
217 | static int __init set_pci_reboot(const struct dmi_system_id *d) | ||
218 | { | ||
219 | if (reboot_type != BOOT_CF9) { | ||
220 | reboot_type = BOOT_CF9; | ||
221 | printk(KERN_INFO "%s series board detected. " | ||
222 | "Selecting PCI-method for reboots.\n", d->ident); | ||
223 | } | ||
224 | return 0; | ||
225 | } | ||
226 | |||
153 | static int __init set_kbd_reboot(const struct dmi_system_id *d) | 227 | static int __init set_kbd_reboot(const struct dmi_system_id *d) |
154 | { | 228 | { |
155 | if (reboot_type != BOOT_KBD) { | 229 | if (reboot_type != BOOT_KBD) { |
@@ -159,7 +233,11 @@ static int __init set_kbd_reboot(const struct dmi_system_id *d) | |||
159 | return 0; | 233 | return 0; |
160 | } | 234 | } |
161 | 235 | ||
236 | /* This is a single dmi_table handling all reboot quirks. Note that | ||
237 | * REBOOT_BIOS is only available for 32bit | ||
238 | */ | ||
162 | static struct dmi_system_id __initdata reboot_dmi_table[] = { | 239 | static struct dmi_system_id __initdata reboot_dmi_table[] = { |
240 | #ifdef CONFIG_X86_32 | ||
163 | { /* Handle problems with rebooting on Dell E520's */ | 241 | { /* Handle problems with rebooting on Dell E520's */ |
164 | .callback = set_bios_reboot, | 242 | .callback = set_bios_reboot, |
165 | .ident = "Dell E520", | 243 | .ident = "Dell E520", |
@@ -309,6 +387,8 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
309 | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), | 387 | DMI_MATCH(DMI_BOARD_NAME, "P4S800"), |
310 | }, | 388 | }, |
311 | }, | 389 | }, |
390 | #endif /* CONFIG_X86_32 */ | ||
391 | |||
312 | { /* Handle reboot issue on Acer Aspire one */ | 392 | { /* Handle reboot issue on Acer Aspire one */ |
313 | .callback = set_kbd_reboot, | 393 | .callback = set_kbd_reboot, |
314 | .ident = "Acer Aspire One A110", | 394 | .ident = "Acer Aspire One A110", |
@@ -317,96 +397,6 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
317 | DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), | 397 | DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"), |
318 | }, | 398 | }, |
319 | }, | 399 | }, |
320 | { } | ||
321 | }; | ||
322 | |||
323 | static int __init reboot_init(void) | ||
324 | { | ||
325 | /* Only do the DMI check if reboot_type hasn't been overridden | ||
326 | * on the command line | ||
327 | */ | ||
328 | if (reboot_default) { | ||
329 | dmi_check_system(reboot_dmi_table); | ||
330 | } | ||
331 | return 0; | ||
332 | } | ||
333 | core_initcall(reboot_init); | ||
334 | |||
335 | extern const unsigned char machine_real_restart_asm[]; | ||
336 | extern const u64 machine_real_restart_gdt[3]; | ||
337 | |||
338 | void machine_real_restart(unsigned int type) | ||
339 | { | ||
340 | void *restart_va; | ||
341 | unsigned long restart_pa; | ||
342 | void (*restart_lowmem)(unsigned int); | ||
343 | u64 *lowmem_gdt; | ||
344 | |||
345 | local_irq_disable(); | ||
346 | |||
347 | /* Write zero to CMOS register number 0x0f, which the BIOS POST | ||
348 | routine will recognize as telling it to do a proper reboot. (Well | ||
349 | that's what this book in front of me says -- it may only apply to | ||
350 | the Phoenix BIOS though, it's not clear). At the same time, | ||
351 | disable NMIs by setting the top bit in the CMOS address register, | ||
352 | as we're about to do peculiar things to the CPU. I'm not sure if | ||
353 | `outb_p' is needed instead of just `outb'. Use it to be on the | ||
354 | safe side. (Yes, CMOS_WRITE does outb_p's. - Paul G.) | ||
355 | */ | ||
356 | spin_lock(&rtc_lock); | ||
357 | CMOS_WRITE(0x00, 0x8f); | ||
358 | spin_unlock(&rtc_lock); | ||
359 | |||
360 | /* | ||
361 | * Switch back to the initial page table. | ||
362 | */ | ||
363 | load_cr3(initial_page_table); | ||
364 | |||
365 | /* Write 0x1234 to absolute memory location 0x472. The BIOS reads | ||
366 | this on booting to tell it to "Bypass memory test (also warm | ||
367 | boot)". This seems like a fairly standard thing that gets set by | ||
368 | REBOOT.COM programs, and the previous reset routine did this | ||
369 | too. */ | ||
370 | *((unsigned short *)0x472) = reboot_mode; | ||
371 | |||
372 | /* Patch the GDT in the low memory trampoline */ | ||
373 | lowmem_gdt = TRAMPOLINE_SYM(machine_real_restart_gdt); | ||
374 | |||
375 | restart_va = TRAMPOLINE_SYM(machine_real_restart_asm); | ||
376 | restart_pa = virt_to_phys(restart_va); | ||
377 | restart_lowmem = (void (*)(unsigned int))restart_pa; | ||
378 | |||
379 | /* GDT[0]: GDT self-pointer */ | ||
380 | lowmem_gdt[0] = | ||
381 | (u64)(sizeof(machine_real_restart_gdt) - 1) + | ||
382 | ((u64)virt_to_phys(lowmem_gdt) << 16); | ||
383 | /* GDT[1]: 64K real mode code segment */ | ||
384 | lowmem_gdt[1] = | ||
385 | GDT_ENTRY(0x009b, restart_pa, 0xffff); | ||
386 | |||
387 | /* Jump to the identity-mapped low memory code */ | ||
388 | restart_lowmem(type); | ||
389 | } | ||
390 | #ifdef CONFIG_APM_MODULE | ||
391 | EXPORT_SYMBOL(machine_real_restart); | ||
392 | #endif | ||
393 | |||
394 | #endif /* CONFIG_X86_32 */ | ||
395 | |||
396 | /* | ||
397 | * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot | ||
398 | */ | ||
399 | static int __init set_pci_reboot(const struct dmi_system_id *d) | ||
400 | { | ||
401 | if (reboot_type != BOOT_CF9) { | ||
402 | reboot_type = BOOT_CF9; | ||
403 | printk(KERN_INFO "%s series board detected. " | ||
404 | "Selecting PCI-method for reboots.\n", d->ident); | ||
405 | } | ||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { | ||
410 | { /* Handle problems with rebooting on Apple MacBook5 */ | 400 | { /* Handle problems with rebooting on Apple MacBook5 */ |
411 | .callback = set_pci_reboot, | 401 | .callback = set_pci_reboot, |
412 | .ident = "Apple MacBook5", | 402 | .ident = "Apple MacBook5", |
@@ -474,17 +464,17 @@ static struct dmi_system_id __initdata pci_reboot_dmi_table[] = { | |||
474 | { } | 464 | { } |
475 | }; | 465 | }; |
476 | 466 | ||
477 | static int __init pci_reboot_init(void) | 467 | static int __init reboot_init(void) |
478 | { | 468 | { |
479 | /* Only do the DMI check if reboot_type hasn't been overridden | 469 | /* Only do the DMI check if reboot_type hasn't been overridden |
480 | * on the command line | 470 | * on the command line |
481 | */ | 471 | */ |
482 | if (reboot_default) { | 472 | if (reboot_default) { |
483 | dmi_check_system(pci_reboot_dmi_table); | 473 | dmi_check_system(reboot_dmi_table); |
484 | } | 474 | } |
485 | return 0; | 475 | return 0; |
486 | } | 476 | } |
487 | core_initcall(pci_reboot_init); | 477 | core_initcall(reboot_init); |
488 | 478 | ||
489 | static inline void kb_wait(void) | 479 | static inline void kb_wait(void) |
490 | { | 480 | { |