iwlagn: leave notification waits on firmware errors
authorJohannes Berg <johannes.berg@intel.com>
Wed, 13 Apr 2011 10:14:49 +0000 (03:14 -0700)
committerWey-Yi Guy <wey-yi.w.guy@intel.com>
Fri, 22 Apr 2011 17:03:03 +0000 (10:03 -0700)
When the firmware encounters an error while the
driver is waiting for a notification, it will
never get that notification. Therefore, instead
of timing out, bail out on errors when waiting
for notifications.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-dev.h

index 828416881d6f0cd6ce7636207a2ed22a430e642d..a29e2e267ee45691f751d750c8e5226b8086aa8d 100644 (file)
@@ -2266,6 +2266,7 @@ void iwlagn_init_notification_wait(struct iwl_priv *priv,
        wait_entry->fn_data = fn_data;
        wait_entry->cmd = cmd;
        wait_entry->triggered = false;
+       wait_entry->aborted = false;
 
        spin_lock_bh(&priv->_agn.notif_wait_lock);
        list_add(&wait_entry->list, &priv->_agn.notif_waits);
@@ -2279,13 +2280,16 @@ int iwlagn_wait_notification(struct iwl_priv *priv,
        int ret;
 
        ret = wait_event_timeout(priv->_agn.notif_waitq,
-                                wait_entry->triggered,
+                                wait_entry->triggered || wait_entry->aborted,
                                 timeout);
 
        spin_lock_bh(&priv->_agn.notif_wait_lock);
        list_del(&wait_entry->list);
        spin_unlock_bh(&priv->_agn.notif_wait_lock);
 
+       if (wait_entry->aborted)
+               return -EIO;
+
        /* return value is always >= 0 */
        if (ret <= 0)
                return -ETIMEDOUT;
index 885167f8168d7b23aa5993d88acdfdc96850e0b8..46d69657407c6acae8d330c051ae868c723beafa 100644 (file)
@@ -867,6 +867,19 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv,
 }
 #endif
 
+static void iwlagn_abort_notification_waits(struct iwl_priv *priv)
+{
+       unsigned long flags;
+       struct iwl_notification_wait *wait_entry;
+
+       spin_lock_irqsave(&priv->_agn.notif_wait_lock, flags);
+       list_for_each_entry(wait_entry, &priv->_agn.notif_waits, list)
+               wait_entry->aborted = true;
+       spin_unlock_irqrestore(&priv->_agn.notif_wait_lock, flags);
+
+       wake_up_all(&priv->_agn.notif_waitq);
+}
+
 void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
 {
        unsigned int reload_msec;
@@ -878,6 +891,8 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
        /* Cancel currently queued command. */
        clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
 
+       iwlagn_abort_notification_waits(priv);
+
        /* Keep the restart process from trying to send host
         * commands by clearing the ready bit */
        clear_bit(STATUS_READY, &priv->status);
index d8bf11727aacdde1dbc63228c04c7315189c7b10..03452925bae3e0a2436457e5b4d040e379b71739 100644 (file)
@@ -1110,7 +1110,7 @@ struct iwl_notification_wait {
        void *fn_data;
 
        u8 cmd;
-       bool triggered;
+       bool triggered, aborted;
 };
 
 enum iwl_rxon_context_id {