From e74fe2330a5a721610b2b69652d2ec2ebbd302e0 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 13 Apr 2011 03:14:49 -0700 Subject: [PATCH] iwlagn: leave notification waits on firmware errors 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 Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn-lib.c | 6 +++++- drivers/net/wireless/iwlwifi/iwl-core.c | 15 +++++++++++++++ drivers/net/wireless/iwlwifi/iwl-dev.h | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 828416881d6f..a29e2e267ee4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -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; diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 885167f8168d..46d69657407c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -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); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index d8bf11727aac..03452925bae3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -1110,7 +1110,7 @@ struct iwl_notification_wait { void *fn_data; u8 cmd; - bool triggered; + bool triggered, aborted; }; enum iwl_rxon_context_id { -- 2.11.0