• Rafael J. Wysocki's avatar
    ACPI: EC: Rework flushing of EC work while suspended to idle · 4a9af6ca
    Rafael J. Wysocki authored
    The flushing of pending work in the EC driver uses drain_workqueue()
    to flush the event handling work that can requeue itself via
    advance_transaction(), but this is problematic, because that
    work may also be requeued from the query workqueue.
    
    Namely, if an EC transaction is carried out during the execution of
    a query handler, it involves calling advance_transaction() which
    may queue up the event handling work again.  This causes the kernel
    to complain about attempts to add a work item to the EC event
    workqueue while it is being drained and worst-case it may cause a
    valid event to be skipped.
    
    To avoid this problem, introduce two new counters, events_in_progress
    and queries_in_progress, incremented when a work item is queued on
    the event workqueue or the query workqueue, respectively, and
    decremented at the end of the corresponding work function, and make
    acpi_ec_dispatch_gpe() the workqueues in a loop until the both of
    these counters are zero (or system wakeup is pending) instead of
    calling acpi_ec_flush_work().
    
    At the same time, change __acpi_ec_flush_work() to call
    flush_workqueue() instead of drain_workqueue() to flush the event
    workqueue.
    
    While at it, use the observation that the work item queued in
    acpi_ec_query() cannot be pending at that time, because it is used
    only once, to simplify the code in there.
    
    Additionally, clean up a comment in acpi_ec_query() and adjust white
    space in acpi_ec_event_processor().
    
    Fixes: f0ac20c3 ("ACPI: EC: Fix flushing of pending work")
    Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
    4a9af6ca
internal.h 9.33 KB