• Nathan Lynch's avatar
    [POWERPC] Fix multiple bugs in rtas_ibm_suspend_me code · 8f5c7579
    Nathan Lynch authored
    There are several issues with the rtas_ibm_suspend_me code, which
    enables platform-assisted suspension of an LPAR as covered in PAPR
    2.2.
    
    1.) rtas_ibm_suspend_me uses on_each_cpu() to invoke
    rtas_percpu_suspend_me on all cpus via IPI:
    
    if (on_each_cpu(rtas_percpu_suspend_me, &data, 1, 0))
    ...
    
    'data' is on the calling task's stack, but rtas_ibm_suspend_me takes
    no measures to ensure that all instances of rtas_percpu_suspend_me are
    finished accessing 'data' before returning.  This can result in the
    IPI'd cpus accessing random stack data and getting stuck in H_JOIN.
    
    This is addressed by using an atomic count of workers and a completion
    on the stack.
    
    2.) rtas_percpu_suspend_me is needlessly calling H_JOIN in a loop.
    The only event that can cause a cpu to return from H_JOIN is an H_PROD
    from another cpu or a NMI/system reset.  Each cpu need call H_JOIN
    only once per suspend operation.
    
    Remove the loop and the now unnecessary 'waiting' state variable.
    
    3.) H_JOIN must be called with MSR[EE] off, but lazy interrupt
    disabling may cause the caller of rtas_ibm_suspend_me to call H_JOIN
    with it on; the local_irq_disable() in on_each_cpu() is not
    sufficient.
    
    Fix this by explicitly saving the MSR and clearing the EE bit before
    calling H_JOIN.
    
    4.) H_PROD is being called with the Linux logical cpu number as the
    parameter, not the platform interrupt server value.  (It's also being
    called for all possible cpus, which is harmless, but unnecessary.)
    
    This is fixed by calling H_PROD for each online cpu using
    get_hard_smp_processor_id(cpu) for the argument.
    Signed-off-by: default avatarNathan Lynch <ntl@pobox.com>
    Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
    8f5c7579
rtas.c 21.1 KB