0001
0002 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0003
0004 #include <linux/export.h>
0005 #include <linux/reboot.h>
0006 #include <linux/init.h>
0007 #include <linux/pm.h>
0008 #include <linux/efi.h>
0009 #include <linux/dmi.h>
0010 #include <linux/sched.h>
0011 #include <linux/tboot.h>
0012 #include <linux/delay.h>
0013 #include <linux/objtool.h>
0014 #include <linux/pgtable.h>
0015 #include <acpi/reboot.h>
0016 #include <asm/io.h>
0017 #include <asm/apic.h>
0018 #include <asm/io_apic.h>
0019 #include <asm/desc.h>
0020 #include <asm/hpet.h>
0021 #include <asm/proto.h>
0022 #include <asm/reboot_fixups.h>
0023 #include <asm/reboot.h>
0024 #include <asm/pci_x86.h>
0025 #include <asm/virtext.h>
0026 #include <asm/cpu.h>
0027 #include <asm/nmi.h>
0028 #include <asm/smp.h>
0029
0030 #include <linux/ctype.h>
0031 #include <linux/mc146818rtc.h>
0032 #include <asm/realmode.h>
0033 #include <asm/x86_init.h>
0034 #include <asm/efi.h>
0035
0036
0037
0038
0039 void (*pm_power_off)(void);
0040 EXPORT_SYMBOL(pm_power_off);
0041
0042
0043
0044
0045
0046
0047 static int reboot_emergency;
0048
0049
0050 bool port_cf9_safe = false;
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060 static int __init set_acpi_reboot(const struct dmi_system_id *d)
0061 {
0062 if (reboot_type != BOOT_ACPI) {
0063 reboot_type = BOOT_ACPI;
0064 pr_info("%s series board detected. Selecting %s-method for reboots.\n",
0065 d->ident, "ACPI");
0066 }
0067 return 0;
0068 }
0069
0070
0071
0072
0073
0074 static int __init set_bios_reboot(const struct dmi_system_id *d)
0075 {
0076 if (reboot_type != BOOT_BIOS) {
0077 reboot_type = BOOT_BIOS;
0078 pr_info("%s series board detected. Selecting %s-method for reboots.\n",
0079 d->ident, "BIOS");
0080 }
0081 return 0;
0082 }
0083
0084
0085
0086
0087
0088 static int __init set_efi_reboot(const struct dmi_system_id *d)
0089 {
0090 if (reboot_type != BOOT_EFI && !efi_runtime_disabled()) {
0091 reboot_type = BOOT_EFI;
0092 pr_info("%s series board detected. Selecting EFI-method for reboot.\n", d->ident);
0093 }
0094 return 0;
0095 }
0096
0097 void __noreturn machine_real_restart(unsigned int type)
0098 {
0099 local_irq_disable();
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111 spin_lock(&rtc_lock);
0112 CMOS_WRITE(0x00, 0x8f);
0113 spin_unlock(&rtc_lock);
0114
0115
0116
0117
0118 load_trampoline_pgtable();
0119
0120
0121 #ifdef CONFIG_X86_32
0122 asm volatile("jmpl *%0" : :
0123 "rm" (real_mode_header->machine_real_restart_asm),
0124 "a" (type));
0125 #else
0126 asm volatile("ljmpl *%0" : :
0127 "m" (real_mode_header->machine_real_restart_asm),
0128 "D" (type));
0129 #endif
0130 unreachable();
0131 }
0132 #ifdef CONFIG_APM_MODULE
0133 EXPORT_SYMBOL(machine_real_restart);
0134 #endif
0135 STACK_FRAME_NON_STANDARD(machine_real_restart);
0136
0137
0138
0139
0140 static int __init set_pci_reboot(const struct dmi_system_id *d)
0141 {
0142 if (reboot_type != BOOT_CF9_FORCE) {
0143 reboot_type = BOOT_CF9_FORCE;
0144 pr_info("%s series board detected. Selecting %s-method for reboots.\n",
0145 d->ident, "PCI");
0146 }
0147 return 0;
0148 }
0149
0150 static int __init set_kbd_reboot(const struct dmi_system_id *d)
0151 {
0152 if (reboot_type != BOOT_KBD) {
0153 reboot_type = BOOT_KBD;
0154 pr_info("%s series board detected. Selecting %s-method for reboot.\n",
0155 d->ident, "KBD");
0156 }
0157 return 0;
0158 }
0159
0160
0161
0162
0163 static const struct dmi_system_id reboot_dmi_table[] __initconst = {
0164
0165
0166 {
0167 .callback = set_kbd_reboot,
0168 .ident = "Acer Aspire One A110",
0169 .matches = {
0170 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
0171 DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
0172 },
0173 },
0174 {
0175 .callback = set_efi_reboot,
0176 .ident = "Acer TravelMate X514-51T",
0177 .matches = {
0178 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
0179 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate X514-51T"),
0180 },
0181 },
0182
0183
0184 {
0185 .callback = set_pci_reboot,
0186 .ident = "Apple MacBook5",
0187 .matches = {
0188 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
0189 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"),
0190 },
0191 },
0192 {
0193 .callback = set_pci_reboot,
0194 .ident = "Apple MacBook6,1",
0195 .matches = {
0196 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
0197 DMI_MATCH(DMI_PRODUCT_NAME, "MacBook6,1"),
0198 },
0199 },
0200 {
0201 .callback = set_pci_reboot,
0202 .ident = "Apple MacBookPro5",
0203 .matches = {
0204 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
0205 DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"),
0206 },
0207 },
0208 {
0209 .callback = set_pci_reboot,
0210 .ident = "Apple Macmini3,1",
0211 .matches = {
0212 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
0213 DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"),
0214 },
0215 },
0216 {
0217 .callback = set_pci_reboot,
0218 .ident = "Apple iMac9,1",
0219 .matches = {
0220 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
0221 DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
0222 },
0223 },
0224 {
0225 .callback = set_pci_reboot,
0226 .ident = "Apple iMac10,1",
0227 .matches = {
0228 DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
0229 DMI_MATCH(DMI_PRODUCT_NAME, "iMac10,1"),
0230 },
0231 },
0232
0233
0234 {
0235 .callback = set_pci_reboot,
0236 .ident = "ASRock Q1900DC-ITX",
0237 .matches = {
0238 DMI_MATCH(DMI_BOARD_VENDOR, "ASRock"),
0239 DMI_MATCH(DMI_BOARD_NAME, "Q1900DC-ITX"),
0240 },
0241 },
0242
0243
0244 {
0245 .callback = set_bios_reboot,
0246 .ident = "ASUS P4S800",
0247 .matches = {
0248 DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
0249 DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
0250 },
0251 },
0252 {
0253 .callback = set_acpi_reboot,
0254 .ident = "ASUS EeeBook X205TA",
0255 .matches = {
0256 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
0257 DMI_MATCH(DMI_PRODUCT_NAME, "X205TA"),
0258 },
0259 },
0260 {
0261 .callback = set_acpi_reboot,
0262 .ident = "ASUS EeeBook X205TAW",
0263 .matches = {
0264 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
0265 DMI_MATCH(DMI_PRODUCT_NAME, "X205TAW"),
0266 },
0267 },
0268
0269
0270 {
0271 .callback = set_pci_reboot,
0272 .ident = "Certec BPC600",
0273 .matches = {
0274 DMI_MATCH(DMI_SYS_VENDOR, "Certec"),
0275 DMI_MATCH(DMI_PRODUCT_NAME, "BPC600"),
0276 },
0277 },
0278
0279
0280 {
0281 .callback = set_bios_reboot,
0282 .ident = "Dell DXP061",
0283 .matches = {
0284 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0285 DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"),
0286 },
0287 },
0288 {
0289 .callback = set_bios_reboot,
0290 .ident = "Dell E520",
0291 .matches = {
0292 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0293 DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
0294 },
0295 },
0296 {
0297 .callback = set_pci_reboot,
0298 .ident = "Dell Latitude E5410",
0299 .matches = {
0300 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0301 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5410"),
0302 },
0303 },
0304 {
0305 .callback = set_pci_reboot,
0306 .ident = "Dell Latitude E5420",
0307 .matches = {
0308 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0309 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"),
0310 },
0311 },
0312 {
0313 .callback = set_pci_reboot,
0314 .ident = "Dell Latitude E6320",
0315 .matches = {
0316 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0317 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"),
0318 },
0319 },
0320 {
0321 .callback = set_pci_reboot,
0322 .ident = "Dell Latitude E6420",
0323 .matches = {
0324 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0325 DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"),
0326 },
0327 },
0328 {
0329 .callback = set_bios_reboot,
0330 .ident = "Dell OptiPlex 330",
0331 .matches = {
0332 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0333 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"),
0334 DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
0335 },
0336 },
0337 {
0338 .callback = set_bios_reboot,
0339 .ident = "Dell OptiPlex 360",
0340 .matches = {
0341 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0342 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"),
0343 DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
0344 },
0345 },
0346 {
0347 .callback = set_bios_reboot,
0348 .ident = "Dell OptiPlex 745",
0349 .matches = {
0350 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0351 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
0352 },
0353 },
0354 {
0355 .callback = set_bios_reboot,
0356 .ident = "Dell OptiPlex 745",
0357 .matches = {
0358 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0359 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
0360 DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
0361 },
0362 },
0363 {
0364 .callback = set_bios_reboot,
0365 .ident = "Dell OptiPlex 745",
0366 .matches = {
0367 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0368 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
0369 DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
0370 },
0371 },
0372 {
0373 .callback = set_bios_reboot,
0374 .ident = "Dell OptiPlex 760",
0375 .matches = {
0376 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0377 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"),
0378 DMI_MATCH(DMI_BOARD_NAME, "0G919G"),
0379 },
0380 },
0381 {
0382 .callback = set_pci_reboot,
0383 .ident = "Dell OptiPlex 990 BIOS A0x",
0384 .matches = {
0385 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0386 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"),
0387 DMI_MATCH(DMI_BIOS_VERSION, "A0"),
0388 },
0389 },
0390 {
0391 .callback = set_bios_reboot,
0392 .ident = "Dell PowerEdge 300",
0393 .matches = {
0394 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
0395 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
0396 },
0397 },
0398 {
0399 .callback = set_bios_reboot,
0400 .ident = "Dell PowerEdge 1300",
0401 .matches = {
0402 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
0403 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
0404 },
0405 },
0406 {
0407 .callback = set_bios_reboot,
0408 .ident = "Dell PowerEdge 2400",
0409 .matches = {
0410 DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
0411 DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
0412 },
0413 },
0414 {
0415 .callback = set_pci_reboot,
0416 .ident = "Dell PowerEdge C6100",
0417 .matches = {
0418 DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
0419 DMI_MATCH(DMI_PRODUCT_NAME, "C6100"),
0420 },
0421 },
0422 {
0423 .callback = set_pci_reboot,
0424 .ident = "Dell Precision M6600",
0425 .matches = {
0426 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0427 DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"),
0428 },
0429 },
0430 {
0431 .callback = set_bios_reboot,
0432 .ident = "Dell Precision T5400",
0433 .matches = {
0434 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0435 DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"),
0436 },
0437 },
0438 {
0439 .callback = set_bios_reboot,
0440 .ident = "Dell Precision T7400",
0441 .matches = {
0442 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0443 DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"),
0444 },
0445 },
0446 {
0447 .callback = set_bios_reboot,
0448 .ident = "Dell XPS710",
0449 .matches = {
0450 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0451 DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"),
0452 },
0453 },
0454 {
0455 .callback = set_acpi_reboot,
0456 .ident = "Dell OptiPlex 7450 AIO",
0457 .matches = {
0458 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
0459 DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 7450 AIO"),
0460 },
0461 },
0462
0463
0464 {
0465 .callback = set_bios_reboot,
0466 .ident = "HP Compaq Laptop",
0467 .matches = {
0468 DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
0469 DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
0470 },
0471 },
0472
0473 {
0474 .callback = set_pci_reboot,
0475 .ident = "Zotac ZBOX CI327 nano",
0476 .matches = {
0477 DMI_MATCH(DMI_SYS_VENDOR, "NA"),
0478 DMI_MATCH(DMI_PRODUCT_NAME, "ZBOX-CI327NANO-GS-01"),
0479 },
0480 },
0481
0482
0483 {
0484 .callback = set_bios_reboot,
0485 .ident = "Sony VGN-Z540N",
0486 .matches = {
0487 DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
0488 DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
0489 },
0490 },
0491
0492 { }
0493 };
0494
0495 static int __init reboot_init(void)
0496 {
0497 int rv;
0498
0499
0500
0501
0502
0503 if (!reboot_default)
0504 return 0;
0505
0506
0507
0508
0509
0510
0511 rv = dmi_check_system(reboot_dmi_table);
0512
0513 if (!rv && efi_reboot_required() && !efi_runtime_disabled())
0514 reboot_type = BOOT_EFI;
0515
0516 return 0;
0517 }
0518 core_initcall(reboot_init);
0519
0520 static inline void kb_wait(void)
0521 {
0522 int i;
0523
0524 for (i = 0; i < 0x10000; i++) {
0525 if ((inb(0x64) & 0x02) == 0)
0526 break;
0527 udelay(2);
0528 }
0529 }
0530
0531 static void vmxoff_nmi(int cpu, struct pt_regs *regs)
0532 {
0533 cpu_emergency_vmxoff();
0534 }
0535
0536
0537 static void emergency_vmx_disable_all(void)
0538 {
0539
0540 local_irq_disable();
0541
0542
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552 if (cpu_has_vmx()) {
0553
0554 __cpu_emergency_vmxoff();
0555
0556
0557 nmi_shootdown_cpus(vmxoff_nmi);
0558 }
0559 }
0560
0561
0562 void __attribute__((weak)) mach_reboot_fixups(void)
0563 {
0564 }
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585 static void native_machine_emergency_restart(void)
0586 {
0587 int i;
0588 int attempt = 0;
0589 int orig_reboot_type = reboot_type;
0590 unsigned short mode;
0591
0592 if (reboot_emergency)
0593 emergency_vmx_disable_all();
0594
0595 tboot_shutdown(TB_SHUTDOWN_REBOOT);
0596
0597
0598 mode = reboot_mode == REBOOT_WARM ? 0x1234 : 0;
0599 *((unsigned short *)__va(0x472)) = mode;
0600
0601
0602
0603
0604
0605 if (efi_capsule_pending(NULL)) {
0606 pr_info("EFI capsule is pending, forcing EFI reboot.\n");
0607 reboot_type = BOOT_EFI;
0608 }
0609
0610 for (;;) {
0611
0612 switch (reboot_type) {
0613 case BOOT_ACPI:
0614 acpi_reboot();
0615 reboot_type = BOOT_KBD;
0616 break;
0617
0618 case BOOT_KBD:
0619 mach_reboot_fixups();
0620
0621 for (i = 0; i < 10; i++) {
0622 kb_wait();
0623 udelay(50);
0624 outb(0xfe, 0x64);
0625 udelay(50);
0626 }
0627 if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
0628 attempt = 1;
0629 reboot_type = BOOT_ACPI;
0630 } else {
0631 reboot_type = BOOT_EFI;
0632 }
0633 break;
0634
0635 case BOOT_EFI:
0636 efi_reboot(reboot_mode, NULL);
0637 reboot_type = BOOT_BIOS;
0638 break;
0639
0640 case BOOT_BIOS:
0641 machine_real_restart(MRR_BIOS);
0642
0643
0644 reboot_type = BOOT_CF9_SAFE;
0645 break;
0646
0647 case BOOT_CF9_FORCE:
0648 port_cf9_safe = true;
0649 fallthrough;
0650
0651 case BOOT_CF9_SAFE:
0652 if (port_cf9_safe) {
0653 u8 reboot_code = reboot_mode == REBOOT_WARM ? 0x06 : 0x0E;
0654 u8 cf9 = inb(0xcf9) & ~reboot_code;
0655 outb(cf9|2, 0xcf9);
0656 udelay(50);
0657
0658 outb(cf9|reboot_code, 0xcf9);
0659 udelay(50);
0660 }
0661 reboot_type = BOOT_TRIPLE;
0662 break;
0663
0664 case BOOT_TRIPLE:
0665 idt_invalidate();
0666 __asm__ __volatile__("int3");
0667
0668
0669 reboot_type = BOOT_KBD;
0670 break;
0671 }
0672 }
0673 }
0674
0675 void native_machine_shutdown(void)
0676 {
0677
0678 #ifdef CONFIG_X86_IO_APIC
0679
0680
0681
0682
0683
0684
0685
0686
0687
0688
0689
0690 clear_IO_APIC();
0691 #endif
0692
0693 #ifdef CONFIG_SMP
0694
0695
0696
0697
0698
0699 local_irq_disable();
0700 stop_other_cpus();
0701 #endif
0702
0703 lapic_shutdown();
0704 restore_boot_irq_mode();
0705
0706 #ifdef CONFIG_HPET_TIMER
0707 hpet_disable();
0708 #endif
0709
0710 #ifdef CONFIG_X86_64
0711 x86_platform.iommu_shutdown();
0712 #endif
0713 }
0714
0715 static void __machine_emergency_restart(int emergency)
0716 {
0717 reboot_emergency = emergency;
0718 machine_ops.emergency_restart();
0719 }
0720
0721 static void native_machine_restart(char *__unused)
0722 {
0723 pr_notice("machine restart\n");
0724
0725 if (!reboot_force)
0726 machine_shutdown();
0727 __machine_emergency_restart(0);
0728 }
0729
0730 static void native_machine_halt(void)
0731 {
0732
0733 machine_shutdown();
0734
0735 tboot_shutdown(TB_SHUTDOWN_HALT);
0736
0737 stop_this_cpu(NULL);
0738 }
0739
0740 static void native_machine_power_off(void)
0741 {
0742 if (kernel_can_power_off()) {
0743 if (!reboot_force)
0744 machine_shutdown();
0745 do_kernel_power_off();
0746 }
0747
0748 tboot_shutdown(TB_SHUTDOWN_HALT);
0749 }
0750
0751 struct machine_ops machine_ops __ro_after_init = {
0752 .power_off = native_machine_power_off,
0753 .shutdown = native_machine_shutdown,
0754 .emergency_restart = native_machine_emergency_restart,
0755 .restart = native_machine_restart,
0756 .halt = native_machine_halt,
0757 #ifdef CONFIG_KEXEC_CORE
0758 .crash_shutdown = native_machine_crash_shutdown,
0759 #endif
0760 };
0761
0762 void machine_power_off(void)
0763 {
0764 machine_ops.power_off();
0765 }
0766
0767 void machine_shutdown(void)
0768 {
0769 machine_ops.shutdown();
0770 }
0771
0772 void machine_emergency_restart(void)
0773 {
0774 __machine_emergency_restart(1);
0775 }
0776
0777 void machine_restart(char *cmd)
0778 {
0779 machine_ops.restart(cmd);
0780 }
0781
0782 void machine_halt(void)
0783 {
0784 machine_ops.halt();
0785 }
0786
0787 #ifdef CONFIG_KEXEC_CORE
0788 void machine_crash_shutdown(struct pt_regs *regs)
0789 {
0790 machine_ops.crash_shutdown(regs);
0791 }
0792 #endif
0793
0794
0795
0796 int crashing_cpu = -1;
0797
0798 #if defined(CONFIG_SMP)
0799
0800 static nmi_shootdown_cb shootdown_callback;
0801
0802 static atomic_t waiting_for_crash_ipi;
0803 static int crash_ipi_issued;
0804
0805 static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
0806 {
0807 int cpu;
0808
0809 cpu = raw_smp_processor_id();
0810
0811
0812
0813
0814
0815
0816 if (cpu == crashing_cpu)
0817 return NMI_HANDLED;
0818 local_irq_disable();
0819
0820 shootdown_callback(cpu, regs);
0821
0822 atomic_dec(&waiting_for_crash_ipi);
0823
0824 halt();
0825 for (;;)
0826 cpu_relax();
0827
0828 return NMI_HANDLED;
0829 }
0830
0831
0832
0833
0834
0835
0836
0837
0838 void nmi_shootdown_cpus(nmi_shootdown_cb callback)
0839 {
0840 unsigned long msecs;
0841 local_irq_disable();
0842
0843
0844 crashing_cpu = safe_smp_processor_id();
0845
0846 shootdown_callback = callback;
0847
0848 atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
0849
0850 if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback,
0851 NMI_FLAG_FIRST, "crash"))
0852 return;
0853
0854
0855
0856
0857 wmb();
0858
0859 apic_send_IPI_allbutself(NMI_VECTOR);
0860
0861
0862 WRITE_ONCE(crash_ipi_issued, 1);
0863
0864 msecs = 1000;
0865 while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
0866 mdelay(1);
0867 msecs--;
0868 }
0869
0870
0871 }
0872
0873
0874
0875
0876
0877
0878 void run_crash_ipi_callback(struct pt_regs *regs)
0879 {
0880 if (crash_ipi_issued)
0881 crash_nmi_callback(0, regs);
0882 }
0883
0884
0885 void nmi_panic_self_stop(struct pt_regs *regs)
0886 {
0887 while (1) {
0888
0889 run_crash_ipi_callback(regs);
0890 cpu_relax();
0891 }
0892 }
0893
0894 #else
0895 void nmi_shootdown_cpus(nmi_shootdown_cb callback)
0896 {
0897
0898 }
0899
0900 void run_crash_ipi_callback(struct pt_regs *regs)
0901 {
0902 }
0903 #endif