Commit e649437f authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

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: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 1fc35276
...@@ -890,10 +890,8 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv, ...@@ -890,10 +890,8 @@ void iwl_print_rx_config_cmd(struct iwl_priv *priv,
IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); IWL_DEBUG_RADIO(priv, "u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id));
} }
#endif #endif
/**
* iwl_irq_handle_error - called for HW or SW error interrupt from card void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
*/
void iwl_irq_handle_error(struct iwl_priv *priv)
{ {
unsigned int reload_msec; unsigned int reload_msec;
unsigned long reload_jiffies; unsigned long reload_jiffies;
...@@ -904,18 +902,62 @@ void iwl_irq_handle_error(struct iwl_priv *priv) ...@@ -904,18 +902,62 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
/* Cancel currently queued command. */ /* Cancel currently queued command. */
clear_bit(STATUS_HCMD_ACTIVE, &priv->status); clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
/* Keep the restart process from trying to send host
* commands by clearing the ready bit */
clear_bit(STATUS_READY, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
if (!ondemand) {
/*
* If firmware keep reloading, then it indicate something
* serious wrong and firmware having problem to recover
* from it. Instead of keep trying which will fill the syslog
* and hang the system, let's just stop it
*/
reload_jiffies = jiffies;
reload_msec = jiffies_to_msecs((long) reload_jiffies -
(long) priv->reload_jiffies);
priv->reload_jiffies = reload_jiffies;
if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
priv->reload_count++;
if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
IWL_ERR(priv, "BUG_ON, Stop restarting\n");
return;
}
} else
priv->reload_count = 0;
}
if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
if (priv->cfg->mod_params->restart_fw) {
IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
"Restarting adapter due to uCode error.\n");
queue_work(priv->workqueue, &priv->restart);
} else
IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
"Detected FW error, but not restarting\n");
}
}
/**
* iwl_irq_handle_error - called for HW or SW error interrupt from card
*/
void iwl_irq_handle_error(struct iwl_priv *priv)
{
/* W/A for WiFi/WiMAX coex and WiMAX own the RF */ /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
if (priv->cfg->internal_wimax_coex && if (priv->cfg->internal_wimax_coex &&
(!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) & (!(iwl_read_prph(priv, APMG_CLK_CTRL_REG) &
APMS_CLK_VAL_MRB_FUNC_MODE) || APMS_CLK_VAL_MRB_FUNC_MODE) ||
(iwl_read_prph(priv, APMG_PS_CTRL_REG) & (iwl_read_prph(priv, APMG_PS_CTRL_REG) &
APMG_PS_CTRL_VAL_RESET_REQ))) { APMG_PS_CTRL_VAL_RESET_REQ))) {
wake_up_interruptible(&priv->wait_command_queue);
/* /*
*Keep the restart process from trying to send host * Keep the restart process from trying to send host
* commands by clearing the INIT status bit * commands by clearing the ready bit.
*/ */
clear_bit(STATUS_READY, &priv->status); clear_bit(STATUS_READY, &priv->status);
clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
IWL_ERR(priv, "RF is used by WiMAX\n"); IWL_ERR(priv, "RF is used by WiMAX\n");
return; return;
} }
...@@ -935,38 +977,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv) ...@@ -935,38 +977,7 @@ void iwl_irq_handle_error(struct iwl_priv *priv)
&priv->contexts[IWL_RXON_CTX_BSS]); &priv->contexts[IWL_RXON_CTX_BSS]);
#endif #endif
wake_up_interruptible(&priv->wait_command_queue); iwlagn_fw_error(priv, false);
/* Keep the restart process from trying to send host
* commands by clearing the INIT status bit */
clear_bit(STATUS_READY, &priv->status);
/*
* If firmware keep reloading, then it indicate something
* serious wrong and firmware having problem to recover
* from it. Instead of keep trying which will fill the syslog
* and hang the system, let's just stop it
*/
reload_jiffies = jiffies;
reload_msec = jiffies_to_msecs((long) reload_jiffies -
(long) priv->reload_jiffies);
priv->reload_jiffies = reload_jiffies;
if (reload_msec <= IWL_MIN_RELOAD_DURATION) {
priv->reload_count++;
if (priv->reload_count >= IWL_MAX_CONTINUE_RELOAD_CNT) {
IWL_ERR(priv, "BUG_ON, Stop restarting\n");
return;
}
} else
priv->reload_count = 0;
if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) {
IWL_DEBUG(priv, IWL_DL_FW_ERRORS,
"Restarting adapter due to uCode error.\n");
if (priv->cfg->mod_params->restart_fw)
queue_work(priv->workqueue, &priv->restart);
}
} }
static int iwl_apm_stop_master(struct iwl_priv *priv) static 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,15 +1766,7 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
break; break;
} }
IWL_ERR(priv, "On demand firmware reload\n"); IWL_ERR(priv, "On demand firmware reload\n");
/* Set the FW error flag -- cleared on iwl_down */ iwlagn_fw_error(priv, true);
set_bit(STATUS_FW_ERROR, &priv->status);
wake_up_interruptible(&priv->wait_command_queue);
/*
* Keep the restart process from trying to send host
* commands by clearing the INIT status bit
*/
clear_bit(STATUS_READY, &priv->status);
queue_work(priv->workqueue, &priv->restart);
break; break;
} }
return 0; return 0;
......
...@@ -729,4 +729,7 @@ static inline bool iwl_bt_statistics(struct iwl_priv *priv) ...@@ -729,4 +729,7 @@ static inline bool iwl_bt_statistics(struct iwl_priv *priv)
extern bool bt_coex_active; extern bool bt_coex_active;
extern bool bt_siso_mode; extern bool bt_siso_mode;
void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
#endif /* __iwl_core_h__ */ #endif /* __iwl_core_h__ */
...@@ -474,7 +474,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) ...@@ -474,7 +474,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
} }
if (!is_ct_kill) { if (!is_ct_kill) {
IWL_ERR(priv, "Restarting adapter due to queue full\n"); IWL_ERR(priv, "Restarting adapter due to queue full\n");
queue_work(priv->workqueue, &priv->restart); iwlagn_fw_error(priv, false);
} }
return -ENOSPC; return -ENOSPC;
} }
...@@ -582,7 +582,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, ...@@ -582,7 +582,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
if (nfreed++ > 0) { if (nfreed++ > 0) {
IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx, IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", idx,
q->write_ptr, q->read_ptr); q->write_ptr, q->read_ptr);
queue_work(priv->workqueue, &priv->restart); iwlagn_fw_error(priv, false);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment