• Rafael J. Wysocki's avatar
    ACPICA: Save current masks of enabled GPEs after enable register writes · c50f13c6
    Rafael J. Wysocki authored
    There is a race condition between acpi_hw_disable_all_gpes() or
    acpi_enable_all_wakeup_gpes() and acpi_ev_asynch_enable_gpe() such
    that if the latter wins the race, it may mistakenly enable a GPE
    disabled by the former.  This may lead to premature system wakeups
    during system suspend and potentially to more serious consequences.
    
    The source of the problem is how acpi_hw_low_set_gpe() works when
    passed ACPI_GPE_CONDITIONAL_ENABLE as the second argument.  In that
    case, the GPE will be enabled if the corresponding bit is set in the
    enable_for_run mask of the GPE enable register containing that bit.
    However, acpi_hw_disable_all_gpes() and acpi_enable_all_wakeup_gpes()
    don't modify the enable_for_run masks of GPE registers when writing
    to them.  In consequence, if acpi_ev_asynch_enable_gpe(), which
    eventually calls acpi_hw_low_set_gpe() with the second argument
    equal to ACPI_GPE_CONDITIONAL_ENABLE, is executed in parallel with
    one of these functions, it may reverse changes made by them.
    
    To fix the problem, introduce a new enable_mask field in struct
    acpi_gpe_register_info in which to store the current mask of
    enabled GPEs and modify acpi_hw_low_set_gpe() to take this
    mask into account instead of enable_for_run when its second
    argument is equal to ACPI_GPE_CONDITIONAL_ENABLE.  Also modify
    the low-level routines called by acpi_hw_disable_all_gpes(),
    acpi_enable_all_wakeup_gpes() and acpi_enable_all_runtime_gpes()
    to update the enable_mask masks of GPE registers after all
    (successful) writes to those registers.
    Acked-by: default avatarLv Zheng <lv.zheng@intel.com>
    Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
    c50f13c6
evgpe.c 22.6 KB