aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-04-05 12:41:58 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-04-07 15:51:37 -0400
commite649437fd6e2bae6f7b8a36a302a1ec4faa5d906 (patch)
tree282932c057ba1eccdbc53e47413649c2a077f475 /drivers
parent1fc352765fb461e4afafff4d650624df8ab6b6d6 (diff)
iwlagn: centralize and fix ucode restart
The ucode restart has to take into account a number of things, like clearing the HCMD_ACTIVE and other status bits, and waking up the wait_command_queue. Currently, however, there are a number of places that neither do that, nor actually set the FW error bit that leads to proper restart handling, which means that in those cases things will probably just hang completely. To clean this up, make all ucode restart go through a single function, except for the cases where it's called during firmware loading. Also fix a bug in wimax coexist restart avoidance, it needs to first clear the status bits (and it has to clear the HCMD_ACTIVE one as well) and then wake up anything waiting on wait_command_queue. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c99
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c4
3 files changed, 56 insertions, 50 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index d778f52132cb..64b28b01ad86 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -890,10 +890,8 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv,
890 IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); 890 IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
891} 891}
892#endif 892#endif
893/** 893
894 * iwl_irq_handle_error - called for HW or SW error interrupt from card 894void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
895 */
896void iwl_irq_handle_error(struct iwl_priv *priv)
897{ 895{
898 unsigned int reload_msec; 896 unsigned int reload_msec;
899 unsigned long reload_jiffies; 897 unsigned long reload_jiffies;
@@ -904,18 +902,62 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
904 /* Cancel currently queued command. */ 902 /* Cancel currently queued command. */
905 clear_bit(STATUS_HCMD_ACTIVE, &priv->status); 903 clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
906 904
905 /* Keep the restart process from trying to send host
906 * commands by clearing the ready bit */
907 clear_bit(STATUS_READY, &priv->status);
908
909 wake_up_interruptible(&priv->wait_command_queue);
910
911 if (!ondemand) {
912 /*
913 * If firmware keep reloading, then it indicate something
914 * serious wrong and firmware having problem to recover
915 * from it. Instead of keep trying which will fill the syslog
916 * and hang the system, let's just stop it
917 */
918 reload_jiffies = jiffies;
919 reload_msec = jiffies_to_msecs((long) reload_jiffies -
920 (long) priv->reload_jiffies);
921 priv->reload_jiffies = reload_jiffies;
922 if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
923 priv->reload_count++;
924 if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
925 IWL_ERR(priv, "BUG_ON, Stop restarting\n");
926 return;
927 }
928 } else
929 priv->reload_count = 0;
930 }
931
932 if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
933 if (priv->cfg->mod_params->restart_fw) {
934 IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
935 "Restarting adapter due to uCode error.\n");
936 queue_work(priv->workqueue, &priv->restart);
937 } else
938 IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
939 "Detected FW error, but not restarting\n");
940 }
941}
942
943/**
944 * iwl_irq_handle_error - called for HW or SW error interrupt from card
945 */
946void iwl_irq_handle_error(struct iwl_priv *priv)
947{
907 /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ 948 /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
908 if (priv->cfg->internal_wimax_coex && 949 if (priv->cfg->internal_wimax_coex &&
909 (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) & 950 (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) &
910 APMS_CLK_VAL_MRB_FUNC_MODE) || 951 APMS_CLK_VAL_MRB_FUNC_MODE) ||
911 (iwl_read_prph(priv, APMG_PS_CTRL_REG) & 952 (iwl_read_prph(priv, APMG_PS_CTRL_REG) &
912 APMG_PS_CTRL_VAL_RESET_REQ))) { 953 APMG_PS_CTRL_VAL_RESET_REQ))) {
913 wake_up_interruptible(&priv->wait_command_queue);
914 /* 954 /*
915 *Keep the restart process from trying to send host 955 * Keep the restart process from trying to send host
916 * commands by clearing the INIT status bit 956 * commands by clearing the ready bit.
917 */ 957 */
918 clear_bit(STATUS_READY, &priv->status); 958 clear_bit(STATUS_READY, &priv->status);
959 clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
960 wake_up_interruptible(&priv->wait_command_queue);
919 IWL_ERR(priv, "RF is used by WiMAX\n"); 961 IWL_ERR(priv, "RF is used by WiMAX\n");
920 return; 962 return;
921 } 963 }
@@ -935,38 +977,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
935 &priv->contexts[IWL_RXON_CTX_BSS]); 977 &priv->contexts[IWL_RXON_CTX_BSS]);
936#endif 978#endif
937 979
938 wake_up_interruptible(&priv->wait_command_queue); 980 iwlagn_fw_error(priv, false);
939
940 /* Keep the restart process from trying to send host
941 * commands by clearing the INIT status bit */
942 clear_bit(STATUS_READY, &priv->status);
943
944 /*
945 * If firmware keep reloading, then it indicate something
946 * serious wrong and firmware having problem to recover
947 * from it. Instead of keep trying which will fill the syslog
948 * and hang the system, let's just stop it
949 */
950 reload_jiffies = jiffies;
951 reload_msec = jiffies_to_msecs((long) reload_jiffies -
952 (long) priv->reload_jiffies);
953 priv->reload_jiffies = reload_jiffies;
954 if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
955 priv->reload_count++;
956 if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
957 IWL_ERR(priv, "BUG_ON, Stop restarting\n");
958 return;
959 }
960 } else
961 priv->reload_count = 0;
962
963 if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
964 IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
965 "Restarting adapter due to uCode error.\n");
966
967 if (priv->cfg->mod_params->restart_fw)
968 queue_work(priv->workqueue, &priv->restart);
969 }
970} 981}
971 982
972static int iwl_apm_stop_master(struct iwl_priv *priv) 983static int iwl_apm_stop_master(struct iwl_priv *priv)
@@ -1755,15 +1766,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
1755 break; 1766 break;
1756 } 1767 }
1757 IWL_ERR(priv, "On demand firmware reload\n"); 1768 IWL_ERR(priv, "On demand firmware reload\n");
1758 /* Set the FW error flag -- cleared on iwl_down */ 1769 iwlagn_fw_error(priv, true);
1759 set_bit(STATUS_FW_ERROR, &priv->status);
1760 wake_up_interruptible(&priv->wait_command_queue);
1761 /*
1762 * Keep the restart process from trying to send host
1763 * commands by clearing the INIT status bit
1764 */
1765 clear_bit(STATUS_READY, &priv->status);
1766 queue_work(priv->workqueue, &priv->restart);
1767 break; 1770 break;
1768 } 1771 }
1769 return 0; 1772 return 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 46c90b3cc30a..8bc23468d82c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -729,4 +729,7 @@ static inline bool iwl_bt_statistics(struct iwl_priv *priv)
729extern bool bt_coex_active; 729extern bool bt_coex_active;
730extern bool bt_siso_mode; 730extern bool bt_siso_mode;
731 731
732
733void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
734
732#endif /* __iwl_core_h__ */ 735#endif /* __iwl_core_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 39a4180ee854..fa81df22a103 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -474,7 +474,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
474 } 474 }
475 if (!is_ct_kill) { 475 if (!is_ct_kill) {
476 IWL_ERR(priv, "Restarting adapter due to queue full\n"); 476 IWL_ERR(priv, "Restarting adapter due to queue full\n");
477 queue_work(priv->workqueue, &priv->restart); 477 iwlagn_fw_error(priv, false);
478 } 478 }
479 return -ENOSPC; 479 return -ENOSPC;
480 } 480 }
@@ -582,7 +582,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
582 if (nfreed++ > 0) { 582 if (nfreed++ > 0) {
583 IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx, 583 IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx,
584 q->write_ptr, q->read_ptr); 584 q->write_ptr, q->read_ptr);
585 queue_work(priv->workqueue, &priv->restart); 585 iwlagn_fw_error(priv, false);
586 } 586 }
587 587
588 } 588 }