// SPDX-License-Identifier: GPL-2.0-or-later/* * CPU Microcode Update Driver for Linux * * Copyright (C) 2000-2006 Tigran Aivazian <aivazian.tigran@gmail.com> * 2006 Shaohua Li <shaohua.li@intel.com> * 2013-2016 Borislav Petkov <bp@alien8.de> * * X86 CPU microcode early update for Linux: * * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> * H Peter Anvin" <hpa@zytor.com> * (C) 2015 Borislav Petkov <bp@alien8.de> * * This driver allows to upgrade microcode on x86 processors. */ #define pr_fmt(fmt) "microcode: " fmt #include <linux/stop_machine.h>#include <linux/device/faux.h>#include <linux/syscore_ops.h>#include <linux/miscdevice.h>#include <linux/capability.h>#include <linux/firmware.h>#include <linux/cpumask.h>#include <linux/kernel.h>#include <linux/delay.h>#include <linux/mutex.h>#include <linux/cpu.h>#include <linux/nmi.h>#include <linux/fs.h>#include <linux/mm.h> #include <asm/apic.h>#include <asm/cpu_device_id.h>#include <asm/cpuid/api.h>#include <asm/perf_event.h>#include <asm/processor.h>#include <asm/cmdline.h>#include <asm/msr.h>#include <asm/setup.h> #include "internal.h" static struct microcode_ops *microcode_ops;static bool dis_ucode_ldr; bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV); /* * Those below should be behind CONFIG_MICROCODE_DBG ifdeffery but in * order to not uglify the code with ifdeffery and use IS_ENABLED() * instead, leave them in. When microcode debugging is not enabled, * those are meaningless anyway. *//* base microcode revision for debugging */u32 base_rev;u32 microcode_rev[NR_CPUS] = {}; bool __ro_after_init x86_hypervisor_present; /* * Synchronization. * * All non cpu-hotplug-callback call sites use: * * - cpus_read_lock/unlock() to synchronize with * the cpu-hotplug-callback call sites. * * We guarantee that only a single cpu is being * updated at any particular moment of time. */struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; /* * Those patch levels cannot be updated to newer ones and thus should be final. */static u32 final_levels[] = { 0x01000098, 0x0100009f, 0x010000af, 0, /* T-101 terminator */}; struct early_load_data early_data; /* * Check the current patch level on this CPU. * * Returns: * - true: if update should stop * - false: otherwise */static bool amd_check_current_patch_level(void){ u32 lvl, dummy, i; u32 *levels; if (x86_cpuid_vendor() != X86_VENDOR_AMD) return false; native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy); levels = final_levels; for (i = 0; levels[i]; i++) { if (lvl == levels[i]) return true; } return false;} bool __init microcode_loader_disabled(void){ if (dis_ucode_ldr) return true; /* * Disable when: * * 1) The CPU does not support CPUID, detected below in * load_ucode_bsp(). * * 2) Bit 31 in CPUID[1]:ECX is set * The bit is reserved for hypervisor use. This is still not * completely accurate as XEN PV guests don't see that CPUID bit * set, but that's good enough as they don't land on the BSP * path anyway. * * 3) Certain AMD patch levels are not allowed to be * overwritten. */ if ((x86_hypervisor_present && !IS_ENABLED(CONFIG_MICROCODE_DBG)) || amd_check_current_patch_level()) dis_ucode_ldr = true; return dis_ucode_ldr;} static void __init early_parse_cmdline(void){ char cmd_buf[64] = {}; char *s, *p = cmd_buf; if (cmdline_find_option(boot_command_line, "microcode", cmd_buf, sizeof(cmd_buf)) > 0) { while ((s = strsep(&p, ","))) { if (IS_ENABLED(CONFIG_MICROCODE_DBG)) { if (strstr(s, "base_rev=")) { /* advance to the option arg */ strsep(&s, "="); if (kstrtouint(s, 16, &base_rev)) { ; } } } if (!strcmp("force_minrev", s)) force_minrev = true; if (!strcmp(s, "dis_ucode_ldr")) dis_ucode_ldr = true; } } /* old, compat option */ if (cmdline_find_option_bool(boot_command_line, "dis_ucode_ldr") > 0) dis_ucode_ldr = true;} void __init load_ucode_bsp(void){ unsigned int cpuid_1_eax; bool intel = true; early_parse_cmdline(); if (!cpuid_feature()) dis_ucode_ldr = true; else x86_hypervisor_present = native_cpuid_ecx(1) & BIT(31); if (microcode_loader_disabled()) return; cpuid_1_eax = native_cpuid_eax(1); switch (x86_cpuid_vendor()) { case X86_VENDOR_INTEL: if (x86_family(cpuid_1_eax) < 6) return; break; case X86_VENDOR_AMD: if (x86_family(cpuid_1_eax) < 0x10) return; intel = false; break; default: return; } if (intel) load_ucode_intel_bsp(&early_data); else load_ucode_amd_bsp(&early_data, cpuid_1_eax);} void load_ucode_ap(void){ unsigned int cpuid_1_eax; /* * Can't use microcode_loader_disabled() here - .init section * hell. It doesn't have to either - the BSP variant must've * parsed cmdline already anyway. */ if (dis_ucode_ldr) return; cpuid_1_eax = native_cpuid_eax(1); switch (x86_cpuid_vendor()) { case X86_VENDOR_INTEL: if (x86_family(cpuid_1_eax) >= 6) load_ucode_intel_ap(); break; case X86_VENDOR_AMD: if (x86_family(cpuid_1_eax) >= 0x10) load_ucode_amd_ap(cpuid_1_eax); break; default: break; }} struct cpio_data __init find_microcode_in_initrd(const char *path){#ifdef CONFIG_BLK_DEV_INITRD unsigned long start = 0; size_t size; #ifdef CONFIG_X86_32 size = boot_params.hdr.ramdisk_size; /* Early load on BSP has a temporary mapping. */ if (size) start = initrd_start_early; #else /* CONFIG_X86_64 */ size = (unsigned long)boot_params.ext_ramdisk_size << 32; size |= boot_params.hdr.ramdisk_size; if (size) { start = (unsigned long)boot_params.ext_ramdisk_image << 32; start |= boot_params.hdr.ramdisk_image; start += PAGE_OFFSET; }#endif /* * Fixup the start address: after reserve_initrd() runs, initrd_start * has the virtual address of the beginning of the initrd. It also * possibly relocates the ramdisk. In either case, initrd_start contains * the updated address so use that instead. */ if (initrd_start) start = initrd_start; return find_cpio_data(path, (void *)start, size, NULL);#else /* !CONFIG_BLK_DEV_INITRD */ return (struct cpio_data){ NULL, 0, "" };#endif} static void reload_early_microcode(unsigned int cpu){ int vendor, family; vendor = x86_cpuid_vendor(); family = x86_cpuid_family(); switch (vendor) { case X86_VENDOR_INTEL: if (family >= 6) reload_ucode_intel(); break; case X86_VENDOR_AMD: if (family >= 0x10) reload_ucode_amd(cpu); break; default: break; }} /* fake device for request_firmware */static struct faux_device *microcode_fdev; #ifdef CONFIG_MICROCODE_LATE_LOADING/* * Late loading dance. Why the heavy-handed stomp_machine effort? * * - HT siblings must be idle and not execute other code while the other sibling * is loading microcode in order to avoid any negative interactions caused by * the loading. * * - In addition, microcode update on the cores must be serialized until this * requirement can be relaxed in the future. Right now, this is conservative * and good. */enum sibling_ctrl { /* Spinwait with timeout */ SCTRL_WAIT, /* Invoke the microcode_apply() callback */ SCTRL_APPLY, /* Proceed without invoking the microcode_apply() callback */ SCTRL_DONE,}; struct microcode_ctrl { enum sibling_ctrl ctrl; enum ucode_state result; unsigned int ctrl_cpu; bool nmi_enabled;}; DEFINE_STATIC_KEY_FALSE(microcode_nmi_handler_enable);static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl);static atomic_t late_cpus_in, offline_in_nmi;static unsigned int loops_per_usec;static cpumask_t cpu_offline_mask; static noinstr bool wait_for_cpus(atomic_t *cnt){ unsigned int timeout, loops; WARN_ON_ONCE(raw_atomic_dec_return(cnt) < 0); for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { if (!raw_atomic_read(cnt)) return true; for (loops = 0; loops < loops_per_usec; loops++) cpu_relax(); /* If invoked directly, tickle the NMI watchdog */ if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) { instrumentation_begin(); touch_nmi_watchdog(); instrumentation_end(); } } /* Prevent the late comers from making progress and let them time out */ raw_atomic_inc(cnt); return false;} static noinstr bool wait_for_ctrl(void){ unsigned int timeout, loops; for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { if (raw_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT) return true; for (loops = 0; loops < loops_per_usec; loops++) cpu_relax(); /* If invoked directly, tickle the NMI watchdog */ if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) { instrumentation_begin(); touch_nmi_watchdog(); instrumentation_end(); } } return false;} /* * Protected against instrumentation up to the point where the primary * thread completed the update. See microcode_nmi_handler() for details. */static noinstr bool load_secondary_wait(unsigned int ctrl_cpu){ /* Initial rendezvous to ensure that all CPUs have arrived */ if (!wait_for_cpus(&late_cpus_in)) { raw_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); return false; } /* * Wait for primary threads to complete. If one of them hangs due * to the update, there is no way out. This is non-recoverable * because the CPU might hold locks or resources and confuse the * scheduler, watchdogs etc. There is no way to safely evacuate the * machine. */ if (wait_for_ctrl()) return true; instrumentation_begin(); panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu); instrumentation_end();} /* * Protected against instrumentation up to the point where the primary * thread completed the update. See microcode_nmi_handler() for details. */static noinstr void load_secondary(unsigned int cpu){ unsigned int ctrl_cpu = raw_cpu_read(ucode_ctrl.ctrl_cpu); enum ucode_state ret; if (!load_secondary_wait(ctrl_cpu)) { instrumentation_begin(); pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1); instrumentation_end(); return; } /* Primary thread completed. Allow to invoke instrumentable code */ instrumentation_begin(); /* * If the primary succeeded then invoke the apply() callback, * otherwise copy the state from the primary thread. */ if (this_cpu_read(ucode_ctrl.ctrl) == SCTRL_APPLY) ret = microcode_ops->apply_microcode(cpu); else ret = per_cpu(ucode_ctrl.result, ctrl_cpu); this_cpu_write(ucode_ctrl.result, ret); this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE); instrumentation_end();} static void __load_primary(unsigned int cpu){ struct cpumask *secondaries = topology_sibling_cpumask(cpu); enum sibling_ctrl ctrl; enum ucode_state ret; unsigned int sibling; /* Initial rendezvous to ensure that all CPUs have arrived */ if (!wait_for_cpus(&late_cpus_in)) { this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1); return; } ret = microcode_ops->apply_microcode(cpu); this_cpu_write(ucode_ctrl.result, ret); this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE); /* * If the update was successful, let the siblings run the apply() * callback. If not, tell them it's done. This also covers the * case where the CPU has uniform loading at package or system * scope implemented but does not advertise it. */ if (ret == UCODE_UPDATED || ret == UCODE_OK) ctrl = SCTRL_APPLY; else ctrl = SCTRL_DONE; for_each_cpu(sibling, secondaries) { if (sibling != cpu) per_cpu(ucode_ctrl.ctrl, sibling) = ctrl; }} static bool kick_offline_cpus(unsigned int nr_offl){ unsigned int cpu, timeout; for_each_cpu(cpu, &cpu_offline_mask) { /* Enable the rendezvous handler and send NMI */ per_cpu(ucode_ctrl.nmi_enabled, cpu) = true; apic_send_nmi_to_offline_cpu(cpu); } /* Wait for them to arrive */ for (timeout = 0; timeout < (USEC_PER_SEC / 2); timeout++) { if (atomic_read(&offline_in_nmi) == nr_offl) return true; udelay(1); } /* Let the others time out */ return false;} static void release_offline_cpus(void){ unsigned int cpu; for_each_cpu(cpu, &cpu_offline_mask) per_cpu(ucode_ctrl.ctrl, cpu) = SCTRL_DONE;} Lines 1–500 of 933. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * CPU Microcode Update Driver for Linux * * Copyright (C) 2000-2006 Tigran Aivazian <aivazian.tigran@gmail.com> * 2006 Shaohua Li <shaohua.li@intel.com> * 2013-2016 Borislav Petkov <bp@alien8.de> * * X86 CPU microcode early update for Linux: * * Copyright (C) 2012 Fenghua Yu <fenghua.yu@intel.com> * H Peter Anvin" <hpa@zytor.com> * (C) 2015 Borislav Petkov <bp@alien8.de> * * This driver allows to upgrade microcode on x86 processors. */ #define pr_fmt(fmt) "microcode: " fmt #include <linux/stop_machine.h> #include <linux/device/faux.h> #include <linux/syscore_ops.h> #include <linux/miscdevice.h> #include <linux/capability.h> #include <linux/firmware.h> #include <linux/cpumask.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/mutex.h> #include <linux/cpu.h> #include <linux/nmi.h> #include <linux/fs.h> #include <linux/mm.h> #include <asm/apic.h> #include <asm/cpu_device_id.h> #include <asm/cpuid/api.h> #include <asm/perf_event.h> #include <asm/processor.h> #include <asm/cmdline.h> #include <asm/msr.h> #include <asm/setup.h> #include "internal.h" static struct microcode_ops *microcode_ops; static bool dis_ucode_ldr; bool force_minrev = IS_ENABLED(CONFIG_MICROCODE_LATE_FORCE_MINREV); /* * Those below should be behind CONFIG_MICROCODE_DBG ifdeffery but in * order to not uglify the code with ifdeffery and use IS_ENABLED() * instead, leave them in. When microcode debugging is not enabled, * those are meaningless anyway. */ /* base microcode revision for debugging */ u32 base_rev; u32 microcode_rev[NR_CPUS] = {}; bool __ro_after_init x86_hypervisor_present; /* * Synchronization. * * All non cpu-hotplug-callback call sites use: * * - cpus_read_lock/unlock() to synchronize with * the cpu-hotplug-callback call sites. * * We guarantee that only a single cpu is being * updated at any particular moment of time. */ struct ucode_cpu_info ucode_cpu_info[NR_CPUS]; /* * Those patch levels cannot be updated to newer ones and thus should be final. */ static u32 final_levels[] = { 0x01000098, 0x0100009f, 0x010000af, 0, /* T-101 terminator */ }; struct early_load_data early_data; /* * Check the current patch level on this CPU. * * Returns: * - true: if update should stop * - false: otherwise */ static bool amd_check_current_patch_level(void) { u32 lvl, dummy, i; u32 *levels; if (x86_cpuid_vendor() != X86_VENDOR_AMD) return false; native_rdmsr(MSR_AMD64_PATCH_LEVEL, lvl, dummy); levels = final_levels; for (i = 0; levels[i]; i++) { if (lvl == levels[i]) return true; } return false; } bool __init microcode_loader_disabled(void) { if (dis_ucode_ldr) return true; /* * Disable when: * * 1) The CPU does not support CPUID, detected below in * load_ucode_bsp(). * * 2) Bit 31 in CPUID[1]:ECX is set * The bit is reserved for hypervisor use. This is still not * completely accurate as XEN PV guests don't see that CPUID bit * set, but that's good enough as they don't land on the BSP * path anyway. * * 3) Certain AMD patch levels are not allowed to be * overwritten. */ if ((x86_hypervisor_present && !IS_ENABLED(CONFIG_MICROCODE_DBG)) || amd_check_current_patch_level()) dis_ucode_ldr = true; return dis_ucode_ldr; } static void __init early_parse_cmdline(void) { char cmd_buf[64] = {}; char *s, *p = cmd_buf; if (cmdline_find_option(boot_command_line, "microcode", cmd_buf, sizeof(cmd_buf)) > 0) { while ((s = strsep(&p, ","))) { if (IS_ENABLED(CONFIG_MICROCODE_DBG)) { if (strstr(s, "base_rev=")) { /* advance to the option arg */ strsep(&s, "="); if (kstrtouint(s, 16, &base_rev)) { ; } } } if (!strcmp("force_minrev", s)) force_minrev = true; if (!strcmp(s, "dis_ucode_ldr")) dis_ucode_ldr = true; } } /* old, compat option */ if (cmdline_find_option_bool(boot_command_line, "dis_ucode_ldr") > 0) dis_ucode_ldr = true; } void __init load_ucode_bsp(void) { unsigned int cpuid_1_eax; bool intel = true; early_parse_cmdline(); if (!cpuid_feature()) dis_ucode_ldr = true; else x86_hypervisor_present = native_cpuid_ecx(1) & BIT(31); if (microcode_loader_disabled()) return; cpuid_1_eax = native_cpuid_eax(1); switch (x86_cpuid_vendor()) { case X86_VENDOR_INTEL: if (x86_family(cpuid_1_eax) < 6) return; break; case X86_VENDOR_AMD: if (x86_family(cpuid_1_eax) < 0x10) return; intel = false; break; default: return; } if (intel) load_ucode_intel_bsp(&early_data); else load_ucode_amd_bsp(&early_data, cpuid_1_eax); } void load_ucode_ap(void) { unsigned int cpuid_1_eax; /* * Can't use microcode_loader_disabled() here - .init section * hell. It doesn't have to either - the BSP variant must've * parsed cmdline already anyway. */ if (dis_ucode_ldr) return; cpuid_1_eax = native_cpuid_eax(1); switch (x86_cpuid_vendor()) { case X86_VENDOR_INTEL: if (x86_family(cpuid_1_eax) >= 6) load_ucode_intel_ap(); break; case X86_VENDOR_AMD: if (x86_family(cpuid_1_eax) >= 0x10) load_ucode_amd_ap(cpuid_1_eax); break; default: break; } } struct cpio_data __init find_microcode_in_initrd(const char *path) { #ifdef CONFIG_BLK_DEV_INITRD unsigned long start = 0; size_t size; #ifdef CONFIG_X86_32 size = boot_params.hdr.ramdisk_size; /* Early load on BSP has a temporary mapping. */ if (size) start = initrd_start_early; #else /* CONFIG_X86_64 */ size = (unsigned long)boot_params.ext_ramdisk_size << 32; size |= boot_params.hdr.ramdisk_size; if (size) { start = (unsigned long)boot_params.ext_ramdisk_image << 32; start |= boot_params.hdr.ramdisk_image; start += PAGE_OFFSET; } #endif /* * Fixup the start address: after reserve_initrd() runs, initrd_start * has the virtual address of the beginning of the initrd. It also * possibly relocates the ramdisk. In either case, initrd_start contains * the updated address so use that instead. */ if (initrd_start) start = initrd_start; return find_cpio_data(path, (void *)start, size, NULL); #else /* !CONFIG_BLK_DEV_INITRD */ return (struct cpio_data){ NULL, 0, "" }; #endif } static void reload_early_microcode(unsigned int cpu) { int vendor, family; vendor = x86_cpuid_vendor(); family = x86_cpuid_family(); switch (vendor) { case X86_VENDOR_INTEL: if (family >= 6) reload_ucode_intel(); break; case X86_VENDOR_AMD: if (family >= 0x10) reload_ucode_amd(cpu); break; default: break; } } /* fake device for request_firmware */ static struct faux_device *microcode_fdev; #ifdef CONFIG_MICROCODE_LATE_LOADING /* * Late loading dance. Why the heavy-handed stomp_machine effort? * * - HT siblings must be idle and not execute other code while the other sibling * is loading microcode in order to avoid any negative interactions caused by * the loading. * * - In addition, microcode update on the cores must be serialized until this * requirement can be relaxed in the future. Right now, this is conservative * and good. */ enum sibling_ctrl { /* Spinwait with timeout */ SCTRL_WAIT, /* Invoke the microcode_apply() callback */ SCTRL_APPLY, /* Proceed without invoking the microcode_apply() callback */ SCTRL_DONE, }; struct microcode_ctrl { enum sibling_ctrl ctrl; enum ucode_state result; unsigned int ctrl_cpu; bool nmi_enabled; }; DEFINE_STATIC_KEY_FALSE(microcode_nmi_handler_enable); static DEFINE_PER_CPU(struct microcode_ctrl, ucode_ctrl); static atomic_t late_cpus_in, offline_in_nmi; static unsigned int loops_per_usec; static cpumask_t cpu_offline_mask; static noinstr bool wait_for_cpus(atomic_t *cnt) { unsigned int timeout, loops; WARN_ON_ONCE(raw_atomic_dec_return(cnt) < 0); for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { if (!raw_atomic_read(cnt)) return true; for (loops = 0; loops < loops_per_usec; loops++) cpu_relax(); /* If invoked directly, tickle the NMI watchdog */ if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) { instrumentation_begin(); touch_nmi_watchdog(); instrumentation_end(); } } /* Prevent the late comers from making progress and let them time out */ raw_atomic_inc(cnt); return false; } static noinstr bool wait_for_ctrl(void) { unsigned int timeout, loops; for (timeout = 0; timeout < USEC_PER_SEC; timeout++) { if (raw_cpu_read(ucode_ctrl.ctrl) != SCTRL_WAIT) return true; for (loops = 0; loops < loops_per_usec; loops++) cpu_relax(); /* If invoked directly, tickle the NMI watchdog */ if (!microcode_ops->use_nmi && !(timeout % USEC_PER_MSEC)) { instrumentation_begin(); touch_nmi_watchdog(); instrumentation_end(); } } return false; } /* * Protected against instrumentation up to the point where the primary * thread completed the update. See microcode_nmi_handler() for details. */ static noinstr bool load_secondary_wait(unsigned int ctrl_cpu) { /* Initial rendezvous to ensure that all CPUs have arrived */ if (!wait_for_cpus(&late_cpus_in)) { raw_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); return false; } /* * Wait for primary threads to complete. If one of them hangs due * to the update, there is no way out. This is non-recoverable * because the CPU might hold locks or resources and confuse the * scheduler, watchdogs etc. There is no way to safely evacuate the * machine. */ if (wait_for_ctrl()) return true; instrumentation_begin(); panic("Microcode load: Primary CPU %d timed out\n", ctrl_cpu); instrumentation_end(); } /* * Protected against instrumentation up to the point where the primary * thread completed the update. See microcode_nmi_handler() for details. */ static noinstr void load_secondary(unsigned int cpu) { unsigned int ctrl_cpu = raw_cpu_read(ucode_ctrl.ctrl_cpu); enum ucode_state ret; if (!load_secondary_wait(ctrl_cpu)) { instrumentation_begin(); pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1); instrumentation_end(); return; } /* Primary thread completed. Allow to invoke instrumentable code */ instrumentation_begin(); /* * If the primary succeeded then invoke the apply() callback, * otherwise copy the state from the primary thread. */ if (this_cpu_read(ucode_ctrl.ctrl) == SCTRL_APPLY) ret = microcode_ops->apply_microcode(cpu); else ret = per_cpu(ucode_ctrl.result, ctrl_cpu); this_cpu_write(ucode_ctrl.result, ret); this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE); instrumentation_end(); } static void __load_primary(unsigned int cpu) { struct cpumask *secondaries = topology_sibling_cpumask(cpu); enum sibling_ctrl ctrl; enum ucode_state ret; unsigned int sibling; /* Initial rendezvous to ensure that all CPUs have arrived */ if (!wait_for_cpus(&late_cpus_in)) { this_cpu_write(ucode_ctrl.result, UCODE_TIMEOUT); pr_err_once("load: %d CPUs timed out\n", atomic_read(&late_cpus_in) - 1); return; } ret = microcode_ops->apply_microcode(cpu); this_cpu_write(ucode_ctrl.result, ret); this_cpu_write(ucode_ctrl.ctrl, SCTRL_DONE); /* * If the update was successful, let the siblings run the apply() * callback. If not, tell them it's done. This also covers the * case where the CPU has uniform loading at package or system * scope implemented but does not advertise it. */ if (ret == UCODE_UPDATED || ret == UCODE_OK) ctrl = SCTRL_APPLY; else ctrl = SCTRL_DONE; for_each_cpu(sibling, secondaries) { if (sibling != cpu) per_cpu(ucode_ctrl.ctrl, sibling) = ctrl; } } static bool kick_offline_cpus(unsigned int nr_offl) { unsigned int cpu, timeout; for_each_cpu(cpu, &cpu_offline_mask) { /* Enable the rendezvous handler and send NMI */ per_cpu(ucode_ctrl.nmi_enabled, cpu) = true; apic_send_nmi_to_offline_cpu(cpu); } /* Wait for them to arrive */ for (timeout = 0; timeout < (USEC_PER_SEC / 2); timeout++) { if (atomic_read(&offline_in_nmi) == nr_offl) return true; udelay(1); } /* Let the others time out */ return false; } static void release_offline_cpus(void) { unsigned int cpu; for_each_cpu(cpu, &cpu_offline_mask) per_cpu(ucode_ctrl.ctrl, cpu) = SCTRL_DONE; }