• Emmanuel Grumbach's avatar
    iwlwifi: split the handler and the wake parts of the notification infra · 2220fb29
    Emmanuel Grumbach authored
    The notification infrastructure (iwl_notification_wait_*
    functions) allows to wait until a list of notifications
    will come up from the firmware and to run a special handler
    (notif_wait handler) when those are received.
    
    The operation mode notifies the notification infrastructure
    about any Rx being received by the mean of
    iwl_notification_wait_notify() which will do two things:
    1) call the notif_wait handler
    2) wakeup the thread that was waiting for the notification
    
    Typically, only after those two steps happened, the
    operation mode will run its own handler for the notification
    that was received from the firmware. This means that the
    thread that was waiting for that notification can be
    running before the operation mode's handler was called.
    
    When the operation mode's handler is ASYNC, things get even
    worse since the thread that was waiting for the
    notification isn't even guaranteed that the ASYNC callback
    was added to async_handlers_list before it starts to run.
    This means that even calling
    iwl_mvm_wait_for_async_handlers() can't guarantee that
    absolutely everything related to that notification has run.
    The following can happen:
    
    Thread sending the command        Operation mode's Rx path
    --------------------------        ------------------------
    iwl_init_notification_wait()
    iwl_mvm_send_cmd()
                                      iwl_mvm_rx_common()
                                      iwl_notification_wait_notify()
    iwl_mvm_wait_for_async_handlers()
    // Possibly free some data
    // structure
                                      list_add_tail(async_handlers_list);
                                      schedule_work(async_handlers_wk);
                                      // Access the freed structure
    
    Split the 'run notif_wait's handler' and the 'wake up the
    thread' parts to fix this. This allows the operation mode
    to do the following:
    
    Thread sending the command        Operation mode's Rx path
    --------------------------        ------------------------
    iwl_init_notification_wait()
    iwl_mvm_send_cmd()
                                      iwl_mvm_rx_common()
                                      iwl_notification_wait()
                                      // Will run the notif_wait's handler
                                      list_add_tail(async_handlers_list);
                                      schedule_work(async_handlers_wk);
                                      iwl_notification_notify()
    iwl_mvm_wait_for_async_handlers()
    
    This way, the waiter is guaranteed that all the handlers
    have been run (if SYNC), or at least enqueued (if ASYNC)
    by the time it wakes up.
    Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
    Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
    2220fb29
iwl-notif-wait.h 5.58 KB