linux/arch/x86/kernel/reboot.c
<<
>>
Prefs
   1#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   2
   3#include <linux/module.h>
   4#include <linux/reboot.h>
   5#include <linux/init.h>
   6#include <linux/pm.h>
   7#include <linux/efi.h>
   8#include <linux/dmi.h>
   9#include <linux/sched.h>
  10#include <linux/tboot.h>
  11#include <linux/delay.h>
  12#include <acpi/reboot.h>
  13#include <asm/io.h>
  14#include <asm/apic.h>
  15#include <asm/desc.h>
  16#include <asm/hpet.h>
  17#include <asm/pgtable.h>
  18#include <asm/proto.h>
  19#include <asm/reboot_fixups.h>
  20#include <asm/reboot.h>
  21#include <asm/pci_x86.h>
  22#include <asm/virtext.h>
  23#include <asm/cpu.h>
  24#include <asm/nmi.h>
  25#include <asm/smp.h>
  26
  27#include <linux/ctype.h>
  28#include <linux/mc146818rtc.h>
  29#include <asm/realmode.h>
  30#include <asm/x86_init.h>
  31
  32/*
  33 * Power off function, if any
  34 */
  35void (*pm_power_off)(void);
  36EXPORT_SYMBOL(pm_power_off);
  37
  38static const struct desc_ptr no_idt = {};
  39
  40/*
  41 * This is set if we need to go through the 'emergency' path.
  42 * When machine_emergency_restart() is called, we may be on
  43 * an inconsistent state and won't be able to do a clean cleanup
  44 */
  45static int reboot_emergency;
  46
  47/* This is set by the PCI code if either type 1 or type 2 PCI is detected */
  48bool port_cf9_safe = false;
  49
  50/*
  51 * Reboot options and system auto-detection code provided by
  52 * Dell Inc. so their systems "just work". :-)
  53 */
  54
  55/*
  56 * Some machines require the "reboot=b" or "reboot=k"  commandline options,
  57 * this quirk makes that automatic.
  58 */
  59static int __init set_bios_reboot(const struct dmi_system_id *d)
  60{
  61        if (reboot_type != BOOT_BIOS) {
  62                reboot_type = BOOT_BIOS;
  63                pr_info("%s series board detected. Selecting %s-method for reboots.\n",
  64                        "BIOS", d->ident);
  65        }
  66        return 0;
  67}
  68
  69void __noreturn machine_real_restart(unsigned int type)
  70{
  71        local_irq_disable();
  72
  73        /*
  74         * Write zero to CMOS register number 0x0f, which the BIOS POST
  75         * routine will recognize as telling it to do a proper reboot.  (Well
  76         * that's what this book in front of me says -- it may only apply to
  77         * the Phoenix BIOS though, it's not clear).  At the same time,
  78         * disable NMIs by setting the top bit in the CMOS address register,
  79         * as we're about to do peculiar things to the CPU.  I'm not sure if
  80         * `outb_p' is needed instead of just `outb'.  Use it to be on the
  81         * safe side.  (Yes, CMOS_WRITE does outb_p's. -  Paul G.)
  82         */
  83        spin_lock(&rtc_lock);
  84        CMOS_WRITE(0x00, 0x8f);
  85        spin_unlock(&rtc_lock);
  86
  87        /*
  88         * Switch back to the initial page table.
  89         */
  90#ifdef CONFIG_X86_32
  91        load_cr3(initial_page_table);
  92#else
  93        write_cr3(real_mode_header->trampoline_pgd);
  94#endif
  95
  96        /* Jump to the identity-mapped low memory code */
  97#ifdef CONFIG_X86_32
  98        asm volatile("jmpl *%0" : :
  99                     "rm" (real_mode_header->machine_real_restart_asm),
 100                     "a" (type));
 101#else
 102        asm volatile("ljmpl *%0" : :
 103                     "m" (real_mode_header->machine_real_restart_asm),
 104                     "D" (type));
 105#endif
 106        unreachable();
 107}
 108#ifdef CONFIG_APM_MODULE
 109EXPORT_SYMBOL(machine_real_restart);
 110#endif
 111
 112/*
 113 * Some Apple MacBook and MacBookPro's needs reboot=p to be able to reboot
 114 */
 115static int __init set_pci_reboot(const struct dmi_system_id *d)
 116{
 117        if (reboot_type != BOOT_CF9) {
 118                reboot_type = BOOT_CF9;
 119                pr_info("%s series board detected. Selecting %s-method for reboots.\n",
 120                        "PCI", d->ident);
 121        }
 122        return 0;
 123}
 124
 125static int __init set_kbd_reboot(const struct dmi_system_id *d)
 126{
 127        if (reboot_type != BOOT_KBD) {
 128                reboot_type = BOOT_KBD;
 129                pr_info("%s series board detected. Selecting %s-method for reboot.\n",
 130                        "KBD", d->ident);
 131        }
 132        return 0;
 133}
 134
 135/*
 136 * This is a single dmi_table handling all reboot quirks.
 137 */
 138static struct dmi_system_id __initdata reboot_dmi_table[] = {
 139        {       /* Handle problems with rebooting on Dell E520's */
 140                .callback = set_bios_reboot,
 141                .ident = "Dell E520",
 142                .matches = {
 143                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 144                        DMI_MATCH(DMI_PRODUCT_NAME, "Dell DM061"),
 145                },
 146        },
 147        {       /* Handle problems with rebooting on Dell 1300's */
 148                .callback = set_bios_reboot,
 149                .ident = "Dell PowerEdge 1300",
 150                .matches = {
 151                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
 152                        DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1300/"),
 153                },
 154        },
 155        {       /* Handle problems with rebooting on Dell 300's */
 156                .callback = set_bios_reboot,
 157                .ident = "Dell PowerEdge 300",
 158                .matches = {
 159                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
 160                        DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 300/"),
 161                },
 162        },
 163        {       /* Handle problems with rebooting on Dell Optiplex 745's SFF */
 164                .callback = set_bios_reboot,
 165                .ident = "Dell OptiPlex 745",
 166                .matches = {
 167                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 168                        DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
 169                },
 170        },
 171        {       /* Handle problems with rebooting on Dell Optiplex 745's DFF */
 172                .callback = set_bios_reboot,
 173                .ident = "Dell OptiPlex 745",
 174                .matches = {
 175                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 176                        DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
 177                        DMI_MATCH(DMI_BOARD_NAME, "0MM599"),
 178                },
 179        },
 180        {       /* Handle problems with rebooting on Dell Optiplex 745 with 0KW626 */
 181                .callback = set_bios_reboot,
 182                .ident = "Dell OptiPlex 745",
 183                .matches = {
 184                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 185                        DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 745"),
 186                        DMI_MATCH(DMI_BOARD_NAME, "0KW626"),
 187                },
 188        },
 189        {       /* Handle problems with rebooting on Dell Optiplex 330 with 0KP561 */
 190                .callback = set_bios_reboot,
 191                .ident = "Dell OptiPlex 330",
 192                .matches = {
 193                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 194                        DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 330"),
 195                        DMI_MATCH(DMI_BOARD_NAME, "0KP561"),
 196                },
 197        },
 198        {       /* Handle problems with rebooting on Dell Optiplex 360 with 0T656F */
 199                .callback = set_bios_reboot,
 200                .ident = "Dell OptiPlex 360",
 201                .matches = {
 202                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 203                        DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 360"),
 204                        DMI_MATCH(DMI_BOARD_NAME, "0T656F"),
 205                },
 206        },
 207        {       /* Handle problems with rebooting on Dell OptiPlex 760 with 0G919G */
 208                .callback = set_bios_reboot,
 209                .ident = "Dell OptiPlex 760",
 210                .matches = {
 211                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 212                        DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 760"),
 213                        DMI_MATCH(DMI_BOARD_NAME, "0G919G"),
 214                },
 215        },
 216        {       /* Handle problems with rebooting on Dell 2400's */
 217                .callback = set_bios_reboot,
 218                .ident = "Dell PowerEdge 2400",
 219                .matches = {
 220                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
 221                        DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2400"),
 222                },
 223        },
 224        {       /* Handle problems with rebooting on Dell T5400's */
 225                .callback = set_bios_reboot,
 226                .ident = "Dell Precision T5400",
 227                .matches = {
 228                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 229                        DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T5400"),
 230                },
 231        },
 232        {       /* Handle problems with rebooting on Dell T7400's */
 233                .callback = set_bios_reboot,
 234                .ident = "Dell Precision T7400",
 235                .matches = {
 236                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 237                        DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation T7400"),
 238                },
 239        },
 240        {       /* Handle problems with rebooting on HP laptops */
 241                .callback = set_bios_reboot,
 242                .ident = "HP Compaq Laptop",
 243                .matches = {
 244                        DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
 245                        DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"),
 246                },
 247        },
 248        {       /* Handle problems with rebooting on Dell XPS710 */
 249                .callback = set_bios_reboot,
 250                .ident = "Dell XPS710",
 251                .matches = {
 252                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 253                        DMI_MATCH(DMI_PRODUCT_NAME, "Dell XPS710"),
 254                },
 255        },
 256        {       /* Handle problems with rebooting on Dell DXP061 */
 257                .callback = set_bios_reboot,
 258                .ident = "Dell DXP061",
 259                .matches = {
 260                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 261                        DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"),
 262                },
 263        },
 264        {       /* Handle problems with rebooting on Sony VGN-Z540N */
 265                .callback = set_bios_reboot,
 266                .ident = "Sony VGN-Z540N",
 267                .matches = {
 268                        DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
 269                        DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"),
 270                },
 271        },
 272        {       /* Handle problems with rebooting on ASUS P4S800 */
 273                .callback = set_bios_reboot,
 274                .ident = "ASUS P4S800",
 275                .matches = {
 276                        DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
 277                        DMI_MATCH(DMI_BOARD_NAME, "P4S800"),
 278                },
 279        },
 280
 281        {       /* Handle reboot issue on Acer Aspire one */
 282                .callback = set_kbd_reboot,
 283                .ident = "Acer Aspire One A110",
 284                .matches = {
 285                        DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 286                        DMI_MATCH(DMI_PRODUCT_NAME, "AOA110"),
 287                },
 288        },
 289        {       /* Handle problems with rebooting on Apple MacBook5 */
 290                .callback = set_pci_reboot,
 291                .ident = "Apple MacBook5",
 292                .matches = {
 293                        DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
 294                        DMI_MATCH(DMI_PRODUCT_NAME, "MacBook5"),
 295                },
 296        },
 297        {       /* Handle problems with rebooting on Apple MacBookPro5 */
 298                .callback = set_pci_reboot,
 299                .ident = "Apple MacBookPro5",
 300                .matches = {
 301                        DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
 302                        DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro5"),
 303                },
 304        },
 305        {       /* Handle problems with rebooting on Apple Macmini3,1 */
 306                .callback = set_pci_reboot,
 307                .ident = "Apple Macmini3,1",
 308                .matches = {
 309                        DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
 310                        DMI_MATCH(DMI_PRODUCT_NAME, "Macmini3,1"),
 311                },
 312        },
 313        {       /* Handle problems with rebooting on the iMac9,1. */
 314                .callback = set_pci_reboot,
 315                .ident = "Apple iMac9,1",
 316                .matches = {
 317                        DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
 318                        DMI_MATCH(DMI_PRODUCT_NAME, "iMac9,1"),
 319                },
 320        },
 321        {       /* Handle problems with rebooting on the Latitude E6320. */
 322                .callback = set_pci_reboot,
 323                .ident = "Dell Latitude E6320",
 324                .matches = {
 325                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 326                        DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6320"),
 327                },
 328        },
 329        {       /* Handle problems with rebooting on the Latitude E5420. */
 330                .callback = set_pci_reboot,
 331                .ident = "Dell Latitude E5420",
 332                .matches = {
 333                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 334                        DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E5420"),
 335                },
 336        },
 337        {       /* Handle problems with rebooting on the Latitude E6420. */
 338                .callback = set_pci_reboot,
 339                .ident = "Dell Latitude E6420",
 340                .matches = {
 341                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 342                        DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6420"),
 343                },
 344        },
 345        {       /* Handle problems with rebooting on the OptiPlex 990. */
 346                .callback = set_pci_reboot,
 347                .ident = "Dell OptiPlex 990",
 348                .matches = {
 349                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 350                        DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 990"),
 351                },
 352        },
 353        {       /* Handle problems with rebooting on the Precision M6600. */
 354                .callback = set_pci_reboot,
 355                .ident = "Dell OptiPlex 990",
 356                .matches = {
 357                        DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
 358                        DMI_MATCH(DMI_PRODUCT_NAME, "Precision M6600"),
 359                },
 360        },
 361        { }
 362};
 363
 364static int __init reboot_init(void)
 365{
 366        /*
 367         * Only do the DMI check if reboot_type hasn't been overridden
 368         * on the command line
 369         */
 370        if (reboot_default)
 371                dmi_check_system(reboot_dmi_table);
 372        return 0;
 373}
 374core_initcall(reboot_init);
 375
 376static inline void kb_wait(void)
 377{
 378        int i;
 379
 380        for (i = 0; i < 0x10000; i++) {
 381                if ((inb(0x64) & 0x02) == 0)
 382                        break;
 383                udelay(2);
 384        }
 385}
 386
 387static void vmxoff_nmi(int cpu, struct pt_regs *regs)
 388{
 389        cpu_emergency_vmxoff();
 390}
 391
 392/* Use NMIs as IPIs to tell all CPUs to disable virtualization */
 393static void emergency_vmx_disable_all(void)
 394{
 395        /* Just make sure we won't change CPUs while doing this */
 396        local_irq_disable();
 397
 398        /*
 399         * We need to disable VMX on all CPUs before rebooting, otherwise
 400         * we risk hanging up the machine, because the CPU ignore INIT
 401         * signals when VMX is enabled.
 402         *
 403         * We can't take any locks and we may be on an inconsistent
 404         * state, so we use NMIs as IPIs to tell the other CPUs to disable
 405         * VMX and halt.
 406         *
 407         * For safety, we will avoid running the nmi_shootdown_cpus()
 408         * stuff unnecessarily, but we don't have a way to check
 409         * if other CPUs have VMX enabled. So we will call it only if the
 410         * CPU we are running on has VMX enabled.
 411         *
 412         * We will miss cases where VMX is not enabled on all CPUs. This
 413         * shouldn't do much harm because KVM always enable VMX on all
 414         * CPUs anyway. But we can miss it on the small window where KVM
 415         * is still enabling VMX.
 416         */
 417        if (cpu_has_vmx() && cpu_vmx_enabled()) {
 418                /* Disable VMX on this CPU. */
 419                cpu_vmxoff();
 420
 421                /* Halt and disable VMX on the other CPUs */
 422                nmi_shootdown_cpus(vmxoff_nmi);
 423
 424        }
 425}
 426
 427
 428void __attribute__((weak)) mach_reboot_fixups(void)
 429{
 430}
 431
 432/*
 433 * Windows compatible x86 hardware expects the following on reboot:
 434 *
 435 * 1) If the FADT has the ACPI reboot register flag set, try it
 436 * 2) If still alive, write to the keyboard controller
 437 * 3) If still alive, write to the ACPI reboot register again
 438 * 4) If still alive, write to the keyboard controller again
 439 *
 440 * If the machine is still alive at this stage, it gives up. We default to
 441 * following the same pattern, except that if we're still alive after (4) we'll
 442 * try to force a triple fault and then cycle between hitting the keyboard
 443 * controller and doing that
 444 */
 445static void native_machine_emergency_restart(void)
 446{
 447        int i;
 448        int attempt = 0;
 449        int orig_reboot_type = reboot_type;
 450        unsigned short mode;
 451
 452        if (reboot_emergency)
 453                emergency_vmx_disable_all();
 454
 455        tboot_shutdown(TB_SHUTDOWN_REBOOT);
 456
 457        /* Tell the BIOS if we want cold or warm reboot */
 458        mode = reboot_mode == REBOOT_WARM ? 0x1234 : 0;
 459        *((unsigned short *)__va(0x472)) = mode;
 460
 461        for (;;) {
 462                /* Could also try the reset bit in the Hammer NB */
 463                switch (reboot_type) {
 464                case BOOT_KBD:
 465                        mach_reboot_fixups(); /* For board specific fixups */
 466
 467                        for (i = 0; i < 10; i++) {
 468                                kb_wait();
 469                                udelay(50);
 470                                outb(0xfe, 0x64); /* Pulse reset low */
 471                                udelay(50);
 472                        }
 473                        if (attempt == 0 && orig_reboot_type == BOOT_ACPI) {
 474                                attempt = 1;
 475                                reboot_type = BOOT_ACPI;
 476                        } else {
 477                                reboot_type = BOOT_TRIPLE;
 478                        }
 479                        break;
 480
 481                case BOOT_TRIPLE:
 482                        load_idt(&no_idt);
 483                        __asm__ __volatile__("int3");
 484
 485                        reboot_type = BOOT_KBD;
 486                        break;
 487
 488                case BOOT_BIOS:
 489                        machine_real_restart(MRR_BIOS);
 490
 491                        reboot_type = BOOT_KBD;
 492                        break;
 493
 494                case BOOT_ACPI:
 495                        acpi_reboot();
 496                        reboot_type = BOOT_KBD;
 497                        break;
 498
 499                case BOOT_EFI:
 500                        if (efi_enabled(EFI_RUNTIME_SERVICES))
 501                                efi.reset_system(reboot_mode == REBOOT_WARM ?
 502                                                 EFI_RESET_WARM :
 503                                                 EFI_RESET_COLD,
 504                                                 EFI_SUCCESS, 0, NULL);
 505                        reboot_type = BOOT_KBD;
 506                        break;
 507
 508                case BOOT_CF9:
 509                        port_cf9_safe = true;
 510                        /* Fall through */
 511
 512                case BOOT_CF9_COND:
 513                        if (port_cf9_safe) {
 514                                u8 cf9 = inb(0xcf9) & ~6;
 515                                outb(cf9|2, 0xcf9); /* Request hard reset */
 516                                udelay(50);
 517                                outb(cf9|6, 0xcf9); /* Actually do the reset */
 518                                udelay(50);
 519                        }
 520                        reboot_type = BOOT_KBD;
 521                        break;
 522                }
 523        }
 524}
 525
 526void native_machine_shutdown(void)
 527{
 528        /* Stop the cpus and apics */
 529#ifdef CONFIG_SMP
 530        /*
 531         * Stop all of the others. Also disable the local irq to
 532         * not receive the per-cpu timer interrupt which may trigger
 533         * scheduler's load balance.
 534         */
 535        local_irq_disable();
 536        stop_other_cpus();
 537#endif
 538
 539        lapic_shutdown();
 540
 541#ifdef CONFIG_X86_IO_APIC
 542        disable_IO_APIC();
 543#endif
 544
 545#ifdef CONFIG_HPET_TIMER
 546        hpet_disable();
 547#endif
 548
 549#ifdef CONFIG_X86_64
 550        x86_platform.iommu_shutdown();
 551#endif
 552}
 553
 554static void __machine_emergency_restart(int emergency)
 555{
 556        reboot_emergency = emergency;
 557        machine_ops.emergency_restart();
 558}
 559
 560static void native_machine_restart(char *__unused)
 561{
 562        pr_notice("machine restart\n");
 563
 564        if (!reboot_force)
 565                machine_shutdown();
 566        __machine_emergency_restart(0);
 567}
 568
 569static void native_machine_halt(void)
 570{
 571        /* Stop other cpus and apics */
 572        machine_shutdown();
 573
 574        tboot_shutdown(TB_SHUTDOWN_HALT);
 575
 576        stop_this_cpu(NULL);
 577}
 578
 579static void native_machine_power_off(void)
 580{
 581        if (pm_power_off) {
 582                if (!reboot_force)
 583                        machine_shutdown();
 584                pm_power_off();
 585        }
 586        /* A fallback in case there is no PM info available */
 587        tboot_shutdown(TB_SHUTDOWN_HALT);
 588}
 589
 590struct machine_ops machine_ops = {
 591        .power_off = native_machine_power_off,
 592        .shutdown = native_machine_shutdown,
 593        .emergency_restart = native_machine_emergency_restart,
 594        .restart = native_machine_restart,
 595        .halt = native_machine_halt,
 596#ifdef CONFIG_KEXEC
 597        .crash_shutdown = native_machine_crash_shutdown,
 598#endif
 599};
 600
 601void machine_power_off(void)
 602{
 603        machine_ops.power_off();
 604}
 605
 606void machine_shutdown(void)
 607{
 608        machine_ops.shutdown();
 609}
 610
 611void machine_emergency_restart(void)
 612{
 613        __machine_emergency_restart(1);
 614}
 615
 616void machine_restart(char *cmd)
 617{
 618        machine_ops.restart(cmd);
 619}
 620
 621void machine_halt(void)
 622{
 623        machine_ops.halt();
 624}
 625
 626#ifdef CONFIG_KEXEC
 627void machine_crash_shutdown(struct pt_regs *regs)
 628{
 629        machine_ops.crash_shutdown(regs);
 630}
 631#endif
 632
 633
 634#if defined(CONFIG_SMP)
 635
 636/* This keeps a track of which one is crashing cpu. */
 637static int crashing_cpu;
 638static nmi_shootdown_cb shootdown_callback;
 639
 640static atomic_t waiting_for_crash_ipi;
 641
 642static int crash_nmi_callback(unsigned int val, struct pt_regs *regs)
 643{
 644        int cpu;
 645
 646        cpu = raw_smp_processor_id();
 647
 648        /*
 649         * Don't do anything if this handler is invoked on crashing cpu.
 650         * Otherwise, system will completely hang. Crashing cpu can get
 651         * an NMI if system was initially booted with nmi_watchdog parameter.
 652         */
 653        if (cpu == crashing_cpu)
 654                return NMI_HANDLED;
 655        local_irq_disable();
 656
 657        shootdown_callback(cpu, regs);
 658
 659        atomic_dec(&waiting_for_crash_ipi);
 660        /* Assume hlt works */
 661        halt();
 662        for (;;)
 663                cpu_relax();
 664
 665        return NMI_HANDLED;
 666}
 667
 668static void smp_send_nmi_allbutself(void)
 669{
 670        apic->send_IPI_allbutself(NMI_VECTOR);
 671}
 672
 673/*
 674 * Halt all other CPUs, calling the specified function on each of them
 675 *
 676 * This function can be used to halt all other CPUs on crash
 677 * or emergency reboot time. The function passed as parameter
 678 * will be called inside a NMI handler on all CPUs.
 679 */
 680void nmi_shootdown_cpus(nmi_shootdown_cb callback)
 681{
 682        unsigned long msecs;
 683        local_irq_disable();
 684
 685        /* Make a note of crashing cpu. Will be used in NMI callback. */
 686        crashing_cpu = safe_smp_processor_id();
 687
 688        shootdown_callback = callback;
 689
 690        atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
 691        /* Would it be better to replace the trap vector here? */
 692        if (register_nmi_handler(NMI_LOCAL, crash_nmi_callback,
 693                                 NMI_FLAG_FIRST, "crash"))
 694                return;         /* Return what? */
 695        /*
 696         * Ensure the new callback function is set before sending
 697         * out the NMI
 698         */
 699        wmb();
 700
 701        smp_send_nmi_allbutself();
 702
 703        msecs = 1000; /* Wait at most a second for the other cpus to stop */
 704        while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
 705                mdelay(1);
 706                msecs--;
 707        }
 708
 709        /* Leave the nmi callback set */
 710}
 711#else /* !CONFIG_SMP */
 712void nmi_shootdown_cpus(nmi_shootdown_cb callback)
 713{
 714        /* No other CPUs to shoot down */
 715}
 716#endif
 717