Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c5ba4a8 authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville
Browse files

iwlwifi: move queue watchdog into transport



This removes one of the two sources of device
restarts in the upper layer -- those are a bit
inconvenient because normal restarts originate
in the transport. By moving the watchdog down
it can be treated the same.

Also rewrite the watchdog logic. Timers are
much more efficient when they never fire, so
instead firing a timer every 500ms set up a
timer for each TX queue and fire it only when
the queue is really stuck. This avoids the CPU
waking up when everything is working well.

While at it, remove the wd_disable config item
and replace it by simply setting wd_timeout to
IWL_WATCHHDOG_DISABLED (0).

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 52bcbff7
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -165,9 +165,8 @@ static const struct iwl_base_params iwl1000_base_params = {
	.support_ct_kill_exit = true,
	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
	.chain_noise_scale = 1000,
	.wd_timeout = IWL_DEF_WD_TIMEOUT,
	.wd_timeout = IWL_WATCHHDOG_DISABLED,
	.max_event_log_size = 128,
	.wd_disable = true,
};

static const struct iwl_ht_params iwl1000_ht_params = {
+1 −2
Original line number Diff line number Diff line
@@ -312,10 +312,9 @@ static const struct iwl_base_params iwl5000_base_params = {
	.led_compensation = 51,
	.plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
	.chain_noise_scale = 1000,
	.wd_timeout = IWL_LONG_WD_TIMEOUT,
	.wd_timeout = IWL_WATCHHDOG_DISABLED,
	.max_event_log_size = 512,
	.no_idle_support = true,
	.wd_disable = true,
};

static const struct iwl_ht_params iwl5000_ht_params = {
+5 −13
Original line number Diff line number Diff line
@@ -741,9 +741,6 @@ int iwl_alive_start(struct iwl_priv *priv)
	/* After the ALIVE response, we can send host commands to the uCode */
	set_bit(STATUS_ALIVE, &priv->status);

	/* Enable watchdog to monitor the driver tx queues */
	iwl_setup_watchdog(priv);

	if (iwl_is_rfkill(priv))
		return -ERFKILL;

@@ -887,10 +884,6 @@ void iwl_down(struct iwl_priv *priv)
	exit_pending =
		test_and_set_bit(STATUS_EXIT_PENDING, &priv->status);

	/* Stop TX queues watchdog. We need to have STATUS_EXIT_PENDING bit set
	 * to prevent rearm timer */
	del_timer_sync(&priv->watchdog);

	iwl_clear_ucode_stations(priv, NULL);
	iwl_dealloc_bcast_stations(priv);
	iwl_clear_driver_stations(priv);
@@ -1092,10 +1085,6 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
	init_timer(&priv->ucode_trace);
	priv->ucode_trace.data = (unsigned long)priv;
	priv->ucode_trace.function = iwl_bg_ucode_trace;

	init_timer(&priv->watchdog);
	priv->watchdog.data = (unsigned long)priv;
	priv->watchdog.function = iwl_bg_watchdog;
}

void iwl_cancel_deferred_work(struct iwl_priv *priv)
@@ -1410,8 +1399,6 @@ static void iwl_set_hw_params(struct iwl_priv *priv)
	if (iwlagn_mod_params.disable_11n & IWL_DISABLE_HT_ALL)
		hw_params(priv).sku &= ~EEPROM_SKU_CAP_11N_ENABLE;

	hw_params(priv).wd_timeout = cfg(priv)->base_params->wd_timeout;

	/* Device-specific setup */
	cfg(priv)->lib->set_hw_params(priv);
}
@@ -1498,6 +1485,11 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
	trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
	trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
	trans_cfg.rx_buf_size_8k = iwlagn_mod_params.amsdu_size_8K;
	if (!iwlagn_mod_params.wd_disable)
		trans_cfg.queue_watchdog_timeout =
			cfg(priv)->base_params->wd_timeout;
	else
		trans_cfg.queue_watchdog_timeout = IWL_WATCHHDOG_DISABLED;

	ucode_flags = fw->ucode_capa.flags;

+0 −68
Original line number Diff line number Diff line
@@ -837,74 +837,6 @@ int iwl_cmd_echo_test(struct iwl_priv *priv)
	return ret;
}

static inline int iwl_check_stuck_queue(struct iwl_priv *priv, int txq)
{
	if (iwl_trans_check_stuck_queue(trans(priv), txq)) {
		int ret;
		ret = iwl_force_reset(priv, IWL_FW_RESET, false);
		return (ret == -EAGAIN) ? 0 : 1;
	}
	return 0;
}

/*
 * Making watchdog tick be a quarter of timeout assure we will
 * discover the queue hung between timeout and 1.25*timeout
 */
#define IWL_WD_TICK(timeout) ((timeout) / 4)

/*
 * Watchdog timer callback, we check each tx queue for stuck, if if hung
 * we reset the firmware. If everything is fine just rearm the timer.
 */
void iwl_bg_watchdog(unsigned long data)
{
	struct iwl_priv *priv = (struct iwl_priv *)data;
	int cnt;
	unsigned long timeout;

	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
		return;

	if (iwl_is_rfkill(priv))
		return;

	timeout = hw_params(priv).wd_timeout;
	if (timeout == 0)
		return;

	/* monitor and check for stuck queues */
	for (cnt = 0; cnt < cfg(priv)->base_params->num_of_queues; cnt++)
		if (iwl_check_stuck_queue(priv, cnt))
			return;

	mod_timer(&priv->watchdog, jiffies +
		  msecs_to_jiffies(IWL_WD_TICK(timeout)));
}

void iwl_setup_watchdog(struct iwl_priv *priv)
{
	unsigned int timeout = hw_params(priv).wd_timeout;

	if (!iwlagn_mod_params.wd_disable) {
		/* use system default */
		if (timeout && !cfg(priv)->base_params->wd_disable)
			mod_timer(&priv->watchdog,
				jiffies +
				msecs_to_jiffies(IWL_WD_TICK(timeout)));
		else
			del_timer(&priv->watchdog);
	} else {
		/* module parameter overwrite default configuration */
		if (timeout && iwlagn_mod_params.wd_disable == 2)
			mod_timer(&priv->watchdog,
				jiffies +
				msecs_to_jiffies(IWL_WD_TICK(timeout)));
		else
			del_timer(&priv->watchdog);
	}
}

/**
 * iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
 * @priv -- pointer to iwl_priv data structure
+0 −2
Original line number Diff line number Diff line
@@ -151,7 +151,6 @@ static inline void iwl_update_stats(struct iwl_priv *priv, bool is_tx,
******************************************************/
void iwl_chswitch_done(struct iwl_priv *priv, bool is_success);

void iwl_setup_watchdog(struct iwl_priv *priv);
/*****************************************************
 * TX power
 ****************************************************/
@@ -193,7 +192,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
 *   S e n d i n g     H o s t     C o m m a n d s   *
 *****************************************************/

void iwl_bg_watchdog(unsigned long data);
u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval);
__le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
			   u32 addon, u32 beacon_interval);
Loading