}
 
 static struct microcode_ops microcode_amd_ops = {
-       .request_microcode_fw             = request_microcode_amd,
-       .collect_cpu_info                 = collect_cpu_info_amd,
-       .apply_microcode                  = apply_microcode_amd,
-       .microcode_fini_cpu               = microcode_fini_cpu_amd,
+       .request_microcode_fw   = request_microcode_amd,
+       .collect_cpu_info       = collect_cpu_info_amd,
+       .apply_microcode        = apply_microcode_amd,
+       .microcode_fini_cpu     = microcode_fini_cpu_amd,
+       .nmi_safe               = true,
 };
 
 struct microcode_ops * __init init_amd_microcode(void)
 
  */
 #define SPINUNIT 100 /* 100 nsec */
 
-static int check_online_cpus(void)
-{
-       unsigned int cpu;
-
-       /*
-        * Make sure all CPUs are online.  It's fine for SMT to be disabled if
-        * all the primary threads are still online.
-        */
-       for_each_present_cpu(cpu) {
-               if (topology_is_primary_thread(cpu) && !cpu_online(cpu)) {
-                       pr_err("Not all CPUs online, aborting microcode update.\n");
-                       return -EINVAL;
-               }
-       }
-
-       return 0;
-}
 
 static atomic_t late_cpus_in;
 static atomic_t late_cpus_out;
        return ret;
 }
 
+/*
+ *  Ensure that all required CPUs which are present and have been booted
+ *  once are online.
+ *
+ *    To pass this check, all primary threads must be online.
+ *
+ *    If the microcode load is not safe against NMI then all SMT threads
+ *    must be online as well because they still react to NMIs when they are
+ *    soft-offlined and parked in one of the play_dead() variants. So if a
+ *    NMI hits while the primary thread updates the microcode the resulting
+ *    behaviour is undefined. The default play_dead() implementation on
+ *    modern CPUs uses MWAIT, which is also not guaranteed to be safe
+ *    against a microcode update which affects MWAIT.
+ */
+static bool ensure_cpus_are_online(void)
+{
+       unsigned int cpu;
+
+       for_each_cpu_and(cpu, cpu_present_mask, &cpus_booted_once_mask) {
+               if (!cpu_online(cpu)) {
+                       if (topology_is_primary_thread(cpu) || !microcode_ops->nmi_safe) {
+                               pr_err("CPU %u not online\n", cpu);
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
 static ssize_t reload_store(struct device *dev,
                            struct device_attribute *attr,
                            const char *buf, size_t size)
 
        cpus_read_lock();
 
-       ret = check_online_cpus();
-       if (ret)
+       if (!ensure_cpus_are_online()) {
+               ret = -EBUSY;
                goto put;
+       }
 
        tmp_ret = microcode_ops->request_microcode_fw(bsp, µcode_pdev->dev);
        if (tmp_ret != UCODE_NEW)
 
 
 struct microcode_ops {
        enum ucode_state (*request_microcode_fw)(int cpu, struct device *dev);
-
        void (*microcode_fini_cpu)(int cpu);
 
        /*
-        * The generic 'microcode_core' part guarantees that
-        * the callbacks below run on a target cpu when they
-        * are being called.
+        * The generic 'microcode_core' part guarantees that the callbacks
+        * below run on a target CPU when they are being called.
         * See also the "Synchronization" section in microcode_core.c.
         */
-       enum ucode_state (*apply_microcode)(int cpu);
-       int (*collect_cpu_info)(int cpu, struct cpu_signature *csig);
-       void (*finalize_late_load)(int result);
+       enum ucode_state        (*apply_microcode)(int cpu);
+       int                     (*collect_cpu_info)(int cpu, struct cpu_signature *csig);
+       void                    (*finalize_late_load)(int result);
+       unsigned int            nmi_safe        : 1;
 };
 
 extern struct ucode_cpu_info ucode_cpu_info[];