iwlagn: avoid hangs when restarting device
authorJohannes Berg <johannes.berg@intel.com>
Tue, 19 Apr 2011 14:38:23 +0000 (07:38 -0700)
committerWey-Yi Guy <wey-yi.w.guy@intel.com>
Sat, 30 Apr 2011 15:39:12 +0000 (08:39 -0700)
If a device error happens while the uCode is
being loaded or initialised, we will attempt
to restart the device (which will likely fail
again, but that's not the issue here). During
this new restart, we turn off the device, but
as the uCode failed to initialise it already
is turned off. As a consequence, grabbing NIC
access will fail and cause excessive messages
and hangs.

To fix this issue, introduce a new status bit
and only attempt to reprogram the device when
it isn't already disabled.

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-core.h

index e202a40cbcb7d5aea88469137a85e09216084785..75e1035330be747592bc7c460e271b2a6ebec4cf 100644 (file)
@@ -2363,12 +2363,21 @@ void iwlagn_stop_device(struct iwl_priv *priv)
        /* device going down, Stop using ICT table */
        iwl_disable_ict(priv);
 
-       iwlagn_txq_ctx_stop(priv);
-       iwlagn_rxq_stop(priv);
-
-       /* Power-down device's busmaster DMA clocks */
-       iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
-       udelay(5);
+       /*
+        * If a HW restart happens during firmware loading,
+        * then the firmware loading might call this function
+        * and later it might be called again due to the
+        * restart. So don't process again if the device is
+        * already dead.
+        */
+       if (test_bit(STATUS_DEVICE_ENABLED, &priv->status)) {
+                iwlagn_txq_ctx_stop(priv);
+                iwlagn_rxq_stop(priv);
+
+                /* Power-down device's busmaster DMA clocks */
+                iwl_write_prph(priv, APMG_CLK_DIS_REG, APMG_CLK_VAL_DMA_CLK_RQT);
+                udelay(5);
+        }
 
        /* Make sure (redundant) we've released our request to stay awake */
        iwl_clear_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
index af72fd51ea74261f197d76c274d6de37c052b695..66da1dec982c6e84b451604ae3028797c4bec515 100644 (file)
@@ -995,6 +995,8 @@ void iwl_apm_stop(struct iwl_priv *priv)
 {
        IWL_DEBUG_INFO(priv, "Stop card, put in low power state\n");
 
+       clear_bit(STATUS_DEVICE_ENABLED, &priv->status);
+
        /* Stop device's DMA activity */
        iwl_apm_stop_master(priv);
 
@@ -1109,6 +1111,8 @@ int iwl_apm_init(struct iwl_priv *priv)
        iwl_set_bits_prph(priv, APMG_PCIDEV_STT_REG,
                          APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
 
+       set_bit(STATUS_DEVICE_ENABLED, &priv->status);
+
 out:
        return ret;
 }
index 32a990ff09ae1c32a8552ddfc2887d982c0c42b3..6226e3d9f10164afa3f0dbee12aae0a8b5b5d41e 100644 (file)
@@ -592,6 +592,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
 #define STATUS_SCAN_HW         15
 #define STATUS_POWER_PMI       16
 #define STATUS_FW_ERROR                17
+#define STATUS_DEVICE_ENABLED  18
 
 
 static inline int iwl_is_ready(struct iwl_priv *priv)