aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/reboot.c
diff options
context:
space:
mode:
authorMichael D Labriola <michael.d.labriola@gmail.com>2012-02-01 10:05:00 -0500
committerIngo Molnar <mingo@elte.hu>2012-02-07 05:34:11 -0500
commit57b165948fe0e1cca78bca1fe1e1ae9a38baedd2 (patch)
treed643576c8705a70f05047b9cb3e4b564f6d8f4df /arch/x86/kernel/reboot.c
parent7915a2e902df9fdb5ea5d5786a4172b38d0ea71e (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.c176
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
153extern const unsigned char machine_real_restart_asm[];
154extern const u64 machine_real_restart_gdt[3];
155
156void 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
209EXPORT_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 */
217static 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
153static int __init set_kbd_reboot(const struct dmi_system_id *d) 227static 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 */
162static struct dmi_system_id __initdata reboot_dmi_table[] = { 239static 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
323static 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}
333core_initcall(reboot_init);
334
335extern const unsigned char machine_real_restart_asm[];
336extern const u64 machine_real_restart_gdt[3];
337
338void 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
391EXPORT_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 */
399static 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
409static 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
477static int __init pci_reboot_init(void) 467static 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}
487core_initcall(pci_reboot_init); 477core_initcall(reboot_init);
488 478
489static inline void kb_wait(void) 479static inline void kb_wait(void)
490{ 480{