• Thomas Gleixner's avatar
    x86/smp: Make stop_other_cpus() more robust · 1f5e7eb7
    Thomas Gleixner authored
    Tony reported intermittent lockups on poweroff. His analysis identified the
    wbinvd() in stop_this_cpu() as the culprit. This was added to ensure that
    on SME enabled machines a kexec() does not leave any stale data in the
    caches when switching from encrypted to non-encrypted mode or vice versa.
    
    That wbinvd() is conditional on the SME feature bit which is read directly
    from CPUID. But that readout does not check whether the CPUID leaf is
    available or not. If it's not available the CPU will return the value of
    the highest supported leaf instead. Depending on the content the "SME" bit
    might be set or not.
    
    That's incorrect but harmless. Making the CPUID readout conditional makes
    the observed hangs go away, but it does not fix the underlying problem:
    
    CPU0					CPU1
    
     stop_other_cpus()
       send_IPIs(REBOOT);			stop_this_cpu()
       while (num_online_cpus() > 1);         set_online(false);
       proceed... -> hang
    				          wbinvd()
    
    WBINVD is an expensive operation and if multiple CPUs issue it at the same
    time the resulting delays are even larger.
    
    But CPU0 already observed num_online_cpus() going down to 1 and proceeds
    which causes the system to hang.
    
    This issue exists independent of WBINVD, but the delays caused by WBINVD
    make it more prominent.
    
    Make this more robust by adding a cpumask which is initialized to the
    online CPU mask before sending the IPIs and CPUs clear their bit in
    stop_this_cpu() after the WBINVD completed. Check for that cpumask to
    become empty in stop_other_cpus() instead of watching num_online_cpus().
    
    The cpumask cannot plug all holes either, but it's better than a raw
    counter and allows to restrict the NMI fallback IPI to be sent only the
    CPUs which have not reported within the timeout window.
    
    Fixes: 08f253ec ("x86/cpu: Clear SME feature flag when not in use")
    Reported-by: default avatarTony Battersby <tonyb@cybernetics.com>
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Reviewed-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
    Reviewed-by: default avatarAshok Raj <ashok.raj@intel.com>
    Cc: stable@vger.kernel.org
    Link: https://lore.kernel.org/all/3817d810-e0f1-8ef8-0bbd-663b919ca49b@cybernetics.com
    Link: https://lore.kernel.org/r/87h6r770bv.ffs@tglx
    1f5e7eb7
smp.c 8.88 KB