Merge branches 'x86-alternatives-for-linus', 'x86-fpu-for-linus', 'x86-hwmon-for...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 6 Jan 2011 19:11:50 +0000 (11:11 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 6 Jan 2011 19:11:50 +0000 (11:11 -0800)
* 'x86-alternatives-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86, suspend: Avoid unnecessary smp alternatives switch during suspend/resume

* 'x86-fpu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86-64, asm: Use fxsaveq/fxrestorq in more places

* 'x86-hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86, hwmon: Add core threshold notification to therm_throt.c

* 'x86-paravirt-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86, paravirt: Use native_halt on a halt, not native_safe_halt

* 'core-locking-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  locking, lockdep: Convert sprintf_symbol to %pS

* 'irq-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  irq: Better struct irqaction layout

1  2  3  4  5  6  7 
arch/x86/include/asm/alternative.h
arch/x86/include/asm/msr-index.h
arch/x86/kernel/alternative.c
arch/x86/kernel/smpboot.c
kernel/cpu.c

index 4a2adaa9aefcc1fe2e42f7c01e29cb3ec61f5842,01171f6c2c3747b51e2e1df0dba4d5c843b24be1,76561d20ea2f27f0edfd0eee6d043b98c6aa6e90,76561d20ea2f27f0edfd0eee6d043b98c6aa6e90,76561d20ea2f27f0edfd0eee6d043b98c6aa6e90,76561d20ea2f27f0edfd0eee6d043b98c6aa6e90,76561d20ea2f27f0edfd0eee6d043b98c6aa6e90..13009d1af99a33e2bbee39fbe80a194fac85ece4
@@@@@@@@ -66,6 -66,7 -66,6 -66,6 -66,6 -66,6 -66,6 +66,7 @@@@@@@@ extern void alternatives_smp_module_add
       extern void alternatives_smp_module_del(struct module *mod);
       extern void alternatives_smp_switch(int smp);
       extern int alternatives_text_reserved(void *start, void *end);
+ +++++extern bool skip_smp_alternatives;
       #else
       static inline void alternatives_smp_module_add(struct module *mod, char *name,
                                               void *locks, void *locks_end,
@@@@@@@@ -180,15 -181,8 -180,8 -180,8 -180,8 -180,8 -180,8 +181,15 @@@@@@@@ extern void *text_poke_early(void *addr
        * On the local CPU you need to be protected again NMI or MCE handlers seeing an
        * inconsistent instruction while you patch.
        */
 ++++++struct text_poke_param {
 ++++++ void *addr;
 ++++++ const void *opcode;
 ++++++ size_t len;
 ++++++};
 ++++++
       extern void *text_poke(void *addr, const void *opcode, size_t len);
       extern void *text_poke_smp(void *addr, const void *opcode, size_t len);
 ++++++extern void text_poke_smp_batch(struct text_poke_param *params, int n);
       
       #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
       #define IDEAL_NOP_SIZE_5 5
index 86030f63ba02cf0947920a2bdd35a1f0d13ea833,6b89f5e860214266d7270160f739e9a9be290802,986f7790fdb2880c4f9efda864a489a0edb83892,622c80b7dbee2aad4f2cbf20a121fbe3a10f2956,6b89f5e860214266d7270160f739e9a9be290802,3ea3dc4870474bdbbb7d0a14e1c43e52c428ddd4,3ea3dc4870474bdbbb7d0a14e1c43e52c428ddd4..4d0dfa0d998e9f80ce244d86e1fd583513aaaaca
       #define MSR_AMD64_IBSDCLINAD             0xc0011038
       #define MSR_AMD64_IBSDCPHYSAD            0xc0011039
       #define MSR_AMD64_IBSCTL         0xc001103a
  +    #define MSR_AMD64_IBSBRTARGET            0xc001103b
  +    
 ++++++/* Fam 15h MSRs */
 ++++++#define MSR_F15H_PERF_CTL                0xc0010200
 ++++++#define MSR_F15H_PERF_CTR                0xc0010201
 + ++++
       /* Fam 10h MSRs */
       #define MSR_FAM10H_MMIO_CONF_BASE        0xc0010058
       #define FAM10H_MMIO_CONF_ENABLE          (1<<0)
       #define FAM10H_MMIO_CONF_BUSRANGE_MASK   0xf
       #define FAM10H_MMIO_CONF_BUSRANGE_SHIFT 2
  -  --#define FAM10H_MMIO_CONF_BASE_MASK       0xfffffff
  +  ++#define FAM10H_MMIO_CONF_BASE_MASK       0xfffffffULL
       #define FAM10H_MMIO_CONF_BASE_SHIFT      20
       #define MSR_FAM10H_NODE_ID               0xc001100c
       
       #define MSR_IA32_TSC                     0x00000010
       #define MSR_IA32_PLATFORM_ID             0x00000017
       #define MSR_IA32_EBL_CR_POWERON          0x0000002a
  +    #define MSR_EBC_FREQUENCY_ID             0x0000002c
       #define MSR_IA32_FEATURE_CONTROL        0x0000003a
       
       #define FEATURE_CONTROL_LOCKED                           (1<<0)
       #define PACKAGE_THERM_INT_LOW_ENABLE             (1 << 1)
       #define PACKAGE_THERM_INT_PLN_ENABLE             (1 << 24)
       
+++ +++/* Thermal Thresholds Support */
+++ +++#define THERM_INT_THRESHOLD0_ENABLE    (1 << 15)
+++ +++#define THERM_SHIFT_THRESHOLD0        8
+++ +++#define THERM_MASK_THRESHOLD0          (0x7f << THERM_SHIFT_THRESHOLD0)
+++ +++#define THERM_INT_THRESHOLD1_ENABLE    (1 << 23)
+++ +++#define THERM_SHIFT_THRESHOLD1        16
+++ +++#define THERM_MASK_THRESHOLD1          (0x7f << THERM_SHIFT_THRESHOLD1)
+++ +++#define THERM_STATUS_THRESHOLD0        (1 << 6)
+++ +++#define THERM_LOG_THRESHOLD0           (1 << 7)
+++ +++#define THERM_STATUS_THRESHOLD1        (1 << 8)
+++ +++#define THERM_LOG_THRESHOLD1           (1 << 9)
+++ +++
       /* MISC_ENABLE bits: architectural */
       #define MSR_IA32_MISC_ENABLE_FAST_STRING (1ULL << 0)
       #define MSR_IA32_MISC_ENABLE_TCC         (1ULL << 1)
index 553d0b0d639bf4b8ef1eca720e7fe43f0fa1e662,9f98eb400fefa9c238822cc3b1ea92ded788e0e1,a36bb90aef5383d68bcf4af0b0c33749d572163a,5079f24c955a2d3b9b66532cd2c8cd45e5116d14,5079f24c955a2d3b9b66532cd2c8cd45e5116d14,5079f24c955a2d3b9b66532cd2c8cd45e5116d14,5079f24c955a2d3b9b66532cd2c8cd45e5116d14..123608531c8f933b819a3fc7c135748137c8eb5b
@@@@@@@@ -353,6 -353,7 -353,6 -353,6 -353,6 -353,6 -353,6 +353,7 @@@@@@@@ void __init_or_module alternatives_smp_
        mutex_unlock(&smp_alt);
       }
       
+ +++++bool skip_smp_alternatives;
       void alternatives_smp_switch(int smp)
       {
        struct smp_alt_module *mod;
        printk("lockdep: fixing up alternatives.\n");
       #endif
       
- ----- if (noreplace_smp || smp_alt_once)
+ +++++ if (noreplace_smp || smp_alt_once || skip_smp_alternatives)
                return;
        BUG_ON(!smp && (num_online_cpus() > 1));
       
@@@@@@@@ -591,21 -592,17 -591,17 -591,17 -591,17 -591,17 -591,17 +592,21 @@@@@@@@ static atomic_t stop_machine_first
       static int wrote_text;
       
       struct text_poke_params {
 ------ void *addr;
 ------ const void *opcode;
 ------ size_t len;
 ++++++ struct text_poke_param *params;
 ++++++ int nparams;
       };
       
       static int __kprobes stop_machine_text_poke(void *data)
       {
        struct text_poke_params *tpp = data;
 ++++++ struct text_poke_param *p;
 ++++++ int i;
       
        if (atomic_dec_and_test(&stop_machine_first)) {
 ------         text_poke(tpp->addr, tpp->opcode, tpp->len);
 ++++++         for (i = 0; i < tpp->nparams; i++) {
 ++++++                 p = &tpp->params[i];
 ++++++                 text_poke(p->addr, p->opcode, p->len);
 ++++++         }
                smp_wmb();      /* Make sure other cpus see that this has run */
                wrote_text = 1;
        } else {
                smp_mb();       /* Load wrote_text before following execution */
        }
       
 ------ flush_icache_range((unsigned long)tpp->addr,
 ------                    (unsigned long)tpp->addr + tpp->len);
 ++++++ for (i = 0; i < tpp->nparams; i++) {
 ++++++         p = &tpp->params[i];
 ++++++         flush_icache_range((unsigned long)p->addr,
 ++++++                            (unsigned long)p->addr + p->len);
 ++++++ }
 ++++++
        return 0;
       }
       
       void *__kprobes text_poke_smp(void *addr, const void *opcode, size_t len)
       {
        struct text_poke_params tpp;
 ++++++ struct text_poke_param p;
       
 ------ tpp.addr = addr;
 ------ tpp.opcode = opcode;
 ------ tpp.len = len;
 ++++++ p.addr = addr;
 ++++++ p.opcode = opcode;
 ++++++ p.len = len;
 ++++++ tpp.params = &p;
 ++++++ tpp.nparams = 1;
        atomic_set(&stop_machine_first, 1);
        wrote_text = 0;
        /* Use __stop_machine() because the caller already got online_cpus. */
  -     __stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
  +     __stop_machine(stop_machine_text_poke, (void *)&tpp, cpu_online_mask);
        return addr;
       }
       
 ++++++/**
 ++++++ * text_poke_smp_batch - Update instructions on a live kernel on SMP
 ++++++ * @params: an array of text_poke parameters
 ++++++ * @n: the number of elements in params.
 ++++++ *
 ++++++ * Modify multi-byte instruction by using stop_machine() on SMP. Since the
 ++++++ * stop_machine() is heavy task, it is better to aggregate text_poke requests
 ++++++ * and do it once if possible.
 ++++++ *
 ++++++ * Note: Must be called under get_online_cpus() and text_mutex.
 ++++++ */
 ++++++void __kprobes text_poke_smp_batch(struct text_poke_param *params, int n)
 ++++++{
 ++++++ struct text_poke_params tpp = {.params = params, .nparams = n};
 ++++++
 ++++++ atomic_set(&stop_machine_first, 1);
 ++++++ wrote_text = 0;
 ++++++ stop_machine(stop_machine_text_poke, (void *)&tpp, NULL);
 ++++++}
 ++++++
       #if defined(CONFIG_DYNAMIC_FTRACE) || defined(HAVE_JUMP_LABEL)
       
  -    unsigned char ideal_nop5[IDEAL_NOP_SIZE_5];
  +    #ifdef CONFIG_X86_64
  +    unsigned char ideal_nop5[5] = { 0x66, 0x66, 0x66, 0x66, 0x90 };
  +    #else
  +    unsigned char ideal_nop5[5] = { 0x3e, 0x8d, 0x74, 0x26, 0x00 };
  +    #endif
       
       void __init arch_init_ideal_nop5(void)
       {
  -     extern const unsigned char ftrace_test_p6nop[];
  -     extern const unsigned char ftrace_test_nop5[];
  -     extern const unsigned char ftrace_test_jmp[];
  -     int faulted = 0;
  -    
        /*
  -      * There is no good nop for all x86 archs.
  -      * We will default to using the P6_NOP5, but first we
  -      * will test to make sure that the nop will actually
  -      * work on this CPU. If it faults, we will then
  -      * go to a lesser efficient 5 byte nop. If that fails
  -      * we then just use a jmp as our nop. This isn't the most
  -      * efficient nop, but we can not use a multi part nop
  -      * since we would then risk being preempted in the middle
  -      * of that nop, and if we enabled tracing then, it might
  -      * cause a system crash.
  +      * There is no good nop for all x86 archs.  This selection
  +      * algorithm should be unified with the one in find_nop_table(),
  +      * but this should be good enough for now.
         *
  -      * TODO: check the cpuid to determine the best nop.
  +      * For cases other than the ones below, use the safe (as in
  +      * always functional) defaults above.
         */
  -     asm volatile (
  -             "ftrace_test_jmp:"
  -             "jmp ftrace_test_p6nop\n"
  -             "nop\n"
  -             "nop\n"
  -             "nop\n"  /* 2 byte jmp + 3 bytes */
  -             "ftrace_test_p6nop:"
  -             P6_NOP5
  -             "jmp 1f\n"
  -             "ftrace_test_nop5:"
  -             ".byte 0x66,0x66,0x66,0x66,0x90\n"
  -             "1:"
  -             ".section .fixup, \"ax\"\n"
  -             "2:     movl $1, %0\n"
  -             "       jmp ftrace_test_nop5\n"
  -             "3:     movl $2, %0\n"
  -             "       jmp 1b\n"
  -             ".previous\n"
  -             _ASM_EXTABLE(ftrace_test_p6nop, 2b)
  -             _ASM_EXTABLE(ftrace_test_nop5, 3b)
  -             : "=r"(faulted) : "0" (faulted));
  -    
  -     switch (faulted) {
  -     case 0:
  -             pr_info("converting mcount calls to 0f 1f 44 00 00\n");
  -             memcpy(ideal_nop5, ftrace_test_p6nop, IDEAL_NOP_SIZE_5);
  -             break;
  -     case 1:
  -             pr_info("converting mcount calls to 66 66 66 66 90\n");
  -             memcpy(ideal_nop5, ftrace_test_nop5, IDEAL_NOP_SIZE_5);
  -             break;
  -     case 2:
  -             pr_info("converting mcount calls to jmp . + 5\n");
  -             memcpy(ideal_nop5, ftrace_test_jmp, IDEAL_NOP_SIZE_5);
  -             break;
  -     }
  -    
  +    #ifdef CONFIG_X86_64
  +     /* Don't use these on 32 bits due to broken virtualizers */
  +     if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL)
  +             memcpy(ideal_nop5, p6_nops[5], 5);
  +    #endif
       }
       #endif
index 68f61ac632e1d814eaa5ab0604505f9b72fc6f80,837c81e99edf6d482320bf20a44710c784159b5e,dfb50890b5b78b59f3843e6087ebc0a7540cc578,083e99d1b7df2aba236563467f47ebb21a09943d,083e99d1b7df2aba236563467f47ebb21a09943d,083e99d1b7df2aba236563467f47ebb21a09943d,083e99d1b7df2aba236563467f47ebb21a09943d..ee886fe10ef4eb8515ae1d2431c0ce8ad3e8dd89
@@@@@@@@ -281,13 -281,6 -281,6 -281,6 -281,6 -281,6 -281,6 +281,13 @@@@@@@@ static void __cpuinit smp_callin(void
         */
        smp_store_cpu_info(cpuid);
       
 ++++++ /*
 ++++++  * This must be done before setting cpu_online_mask
 ++++++  * or calling notify_cpu_starting.
 ++++++  */
 ++++++ set_cpu_sibling_map(raw_smp_processor_id());
 ++++++ wmb();
 ++++++
        notify_cpu_starting(cpuid);
       
        /*
@@@@@@@@ -306,16 -299,16 -299,22 -299,16 -299,16 -299,16 -299,16 +306,16 @@@@@@@@ notrace static void __cpuinit start_sec
         * fragile that we want to limit the things done here to the
         * most necessary things.
         */
  +     cpu_init();
  +     preempt_disable();
  +     smp_callin();
       
       #ifdef CONFIG_X86_32
  -     /*
  -      * Switch away from the trampoline page-table
  -      *
  -      * Do this before cpu_init() because it needs to access per-cpu
  -      * data which may not be mapped in the trampoline page-table.
  -      */
  +     /* switch away from the initial page table */
        load_cr3(swapper_pg_dir);
        __flush_tlb_all();
       #endif
       
  -     cpu_init();
  -     preempt_disable();
  -     smp_callin();
  -    
        /* otherwise gcc will move up smp_processor_id before the cpu_init */
        barrier();
        /*
         */
        check_tsc_sync_target();
       
 ------ if (nmi_watchdog == NMI_IO_APIC) {
 ------         legacy_pic->mask(0);
 ------         enable_NMI_through_LVT0();
 ------         legacy_pic->unmask(0);
 ------ }
 ------
 ------ /* This must be done before setting cpu_online_mask */
 ------ set_cpu_sibling_map(raw_smp_processor_id());
 ------ wmb();
 ------
        /*
         * We need to hold call_lock, so there is no inconsistency
         * between the time smp_call_function() determines number of
@@@@@@@@ -744,7 -747,7 -753,7 -747,7 -747,7 -747,7 -747,7 +744,7 @@@@@@@@ static int __cpuinit do_boot_cpu(int ap
                .done   = COMPLETION_INITIALIZER_ONSTACK(c_idle.done),
        };
       
  -     INIT_WORK_ON_STACK(&c_idle.work, do_fork_idle);
  +     INIT_WORK_ONSTACK(&c_idle.work, do_fork_idle);
       
        alternatives_smp_switch(1);
       
@@@@@@@@ -776,6 -779,6 -785,7 -779,6 -779,6 -779,6 -779,6 +776,6 @@@@@@@@ do_rest
       #ifdef CONFIG_X86_32
        /* Stack for startup_32 can be just as for start_secondary onwards */
        irq_ctx_init(cpu);
  -     initial_page_table = __pa(&trampoline_pg_dir);
       #else
        clear_tsk_thread_flag(c_idle.idle, TIF_FORK);
        initial_gs = per_cpu_offset(cpu);
@@@@@@@@ -924,6 -927,6 -934,7 -927,6 -927,6 -927,6 -927,6 +924,6 @@@@@@@@ int __cpuinit native_cpu_up(unsigned in
        per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
       
        err = do_boot_cpu(apicid, cpu);
  -    
        if (err) {
                pr_debug("do_boot_cpu failed %d\n", err);
                return -EIO;
@@@@@@@@ -1058,6 -1061,8 -1069,8 -1061,8 -1061,8 -1061,8 -1061,8 +1058,6 @@@@@@@@ static int __init smp_sanity_check(unsi
                printk(KERN_INFO "SMP mode deactivated.\n");
                smpboot_clear_io_apic();
       
 ------         localise_nmi_watchdog();
 ------
                connect_bsp_APIC();
                setup_local_APIC();
                end_local_APIC_setup();
        preempt_enable();
       }
       
+ +++++void arch_disable_nonboot_cpus_begin(void)
+ +++++{
+ +++++ /*
+ +++++  * Avoid the smp alternatives switch during the disable_nonboot_cpus().
+ +++++  * In the suspend path, we will be back in the SMP mode shortly anyways.
+ +++++  */
+ +++++ skip_smp_alternatives = true;
+ +++++}
+ +++++
+ +++++void arch_disable_nonboot_cpus_end(void)
+ +++++{
+ +++++ skip_smp_alternatives = false;
+ +++++}
+ +++++
       void arch_enable_nonboot_cpus_begin(void)
       {
        set_mtrr_aps_delayed_init();
@@@@@@@@ -1191,6 -1210,7 -1204,7 -1196,7 -1196,7 -1196,7 -1196,7 +1205,6 @@@@@@@@ void __init native_smp_cpus_done(unsign
       #ifdef CONFIG_X86_IO_APIC
        setup_ioapic_dest();
       #endif
 ------ check_nmi_watchdog();
        mtrr_aps_init();
       }
       
@@@@@@@@ -1335,6 -1355,8 -1349,8 -1341,8 -1341,8 -1341,8 -1341,8 +1349,6 @@@@@@@@ int native_cpu_disable(void
        if (cpu == 0)
                return -EBUSY;
       
 ------ if (nmi_watchdog == NMI_LOCAL_APIC)
 ------         stop_apic_nmi_watchdog(NULL);
        clear_local_APIC();
       
        cpu_disable_common();
@@@@@@@@ -1365,6 -1387,6 -1381,7 -1373,6 -1373,6 -1373,6 -1373,6 +1379,6 @@@@@@@@ void play_dead_common(void
       {
        idle_task_exit();
        reset_lazy_tlbstate();
  -     irq_ctx_exit(raw_smp_processor_id());
        c1e_remove_cpu(raw_smp_processor_id());
       
        mb();
diff --combined kernel/cpu.c
index cb7a1efa9c2b51ac2d97f02a82887638ffa2bf67,8ccc182069ecfc62a3a4331449f46e971ccb40c9,f6e726f184916029e2d1cfdbcd4acb2b26f14e69,f6e726f184916029e2d1cfdbcd4acb2b26f14e69,f6e726f184916029e2d1cfdbcd4acb2b26f14e69,f6e726f184916029e2d1cfdbcd4acb2b26f14e69,f6e726f184916029e2d1cfdbcd4acb2b26f14e69..156cc555614089345553a6e7710580c4f069be0e
@@@@@@@@ -189,6 -189,7 -189,7 -189,7 -189,7 -189,7 -189,7 +189,6 @@@@@@@@ static inline void check_for_tasks(int 
       }
       
       struct take_cpu_down_param {
 ------ struct task_struct *caller;
        unsigned long mod;
        void *hcpu;
       };
       static int __ref take_cpu_down(void *_param)
       {
        struct take_cpu_down_param *param = _param;
 ------ unsigned int cpu = (unsigned long)param->hcpu;
        int err;
       
        /* Ensure this CPU doesn't handle any more interrupts. */
       
        cpu_notify(CPU_DYING | param->mod, param->hcpu);
       
 ------ if (task_cpu(param->caller) == cpu)
 ------         move_task_off_dead_cpu(cpu, param->caller);
 ------ /* Force idle task to run as soon as we yield: it should
 ------    immediately notice cpu is offline and die quickly. */
 ------ sched_idle_next();
        return 0;
       }
       
@@@@@@@@ -216,6 -223,7 -223,7 -223,7 -223,7 -223,7 -223,7 +216,6 @@@@@@@@ static int __ref _cpu_down(unsigned in
        void *hcpu = (void *)(long)cpu;
        unsigned long mod = tasks_frozen ? CPU_TASKS_FROZEN : 0;
        struct take_cpu_down_param tcd_param = {
 ------         .caller = current,
                .mod = mod,
                .hcpu = hcpu,
        };
        }
        BUG_ON(cpu_online(cpu));
       
 ------ /* Wait for it to sleep (leaving idle task). */
 ++++++ /*
 ++++++  * The migration_call() CPU_DYING callback will have removed all
 ++++++  * runnable tasks from the cpu, there's only the idle task left now
 ++++++  * that the migration thread is done doing the stop_machine thing.
 ++++++  *
 ++++++  * Wait for the stop thread to go away.
 ++++++  */
        while (!idle_cpu(cpu))
 ------         yield();
 ++++++         cpu_relax();
       
        /* This actually kills the CPU. */
        __cpu_die(cpu);
       #ifdef CONFIG_PM_SLEEP_SMP
       static cpumask_var_t frozen_cpus;
       
+ +++++void __weak arch_disable_nonboot_cpus_begin(void)
+ +++++{
+ +++++}
+ +++++
+ +++++void __weak arch_disable_nonboot_cpus_end(void)
+ +++++{
+ +++++}
+ +++++
       int disable_nonboot_cpus(void)
       {
        int cpu, first_cpu, error = 0;
         * with the userspace trying to use the CPU hotplug at the same time
         */
        cpumask_clear(frozen_cpus);
+ +++++ arch_disable_nonboot_cpus_begin();
       
        printk("Disabling non-boot CPUs ...\n");
        for_each_online_cpu(cpu) {
                }
        }
       
+ +++++ arch_disable_nonboot_cpus_end();
+ +++++
        if (!error) {
                BUG_ON(num_online_cpus() > 1);
                /* Make sure the CPUs won't be enabled by someone else */