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

Commit a93e7973 authored by Wey-Yi Guy's avatar Wey-Yi Guy Committed by Reinette Chatre
Browse files

iwlwifi: multiple force reset mode



Provide the function to perform different type of uCode reset/reload operation.
When uCode detect error and can not fix itself, this iwl_force_reset()
function allow driver to perform the necessary reset/reload functions and help
to bring uCode back to normal operation state.

Currently only 2 type of force reset are available:
 - reset radio
 - reload firmware

Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: default avatarReinette Chatre <reinette.chatre@intel.com>
parent dff010ac
Loading
Loading
Loading
Loading
+42 −2
Original line number Diff line number Diff line
@@ -3334,7 +3334,7 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
}
EXPORT_SYMBOL(iwl_dump_fh);

void iwl_force_rf_reset(struct iwl_priv *priv)
static void iwl_force_rf_reset(struct iwl_priv *priv)
{
	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
		return;
@@ -3356,7 +3356,47 @@ void iwl_force_rf_reset(struct iwl_priv *priv)
	iwl_internal_short_hw_scan(priv);
	return;
}
EXPORT_SYMBOL(iwl_force_rf_reset);

#define IWL_DELAY_NEXT_FORCE_RESET (HZ*3)

int iwl_force_reset(struct iwl_priv *priv, int mode)
{
	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
		return -EINVAL;

	if (priv->last_force_reset_jiffies &&
	    time_after(priv->last_force_reset_jiffies +
		       IWL_DELAY_NEXT_FORCE_RESET, jiffies)) {
		IWL_DEBUG_INFO(priv, "force reset rejected\n");
		return -EAGAIN;
	}

	IWL_DEBUG_INFO(priv, "perform force reset (%d)\n", mode);

	switch (mode) {
	case IWL_RF_RESET:
		iwl_force_rf_reset(priv);
		break;
	case IWL_FW_RESET:
		IWL_ERR(priv, "On demand firmware reload\n");
		/* Set the FW error flag -- cleared on iwl_down */
		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;
	default:
		IWL_DEBUG_INFO(priv, "invalid reset request.\n");
		return -EINVAL;
	}
	priv->last_force_reset_jiffies = jiffies;

	return 0;
}

#ifdef CONFIG_PM

+1 −1
Original line number Diff line number Diff line
@@ -501,7 +501,7 @@ int iwl_scan_cancel(struct iwl_priv *priv);
int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
int iwl_internal_short_hw_scan(struct iwl_priv *priv);
void iwl_force_rf_reset(struct iwl_priv *priv);
int iwl_force_reset(struct iwl_priv *priv, int mode);
u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
		       const u8 *ie, int ie_len, int left);
void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
+8 −1
Original line number Diff line number Diff line
@@ -1035,6 +1035,11 @@ struct iwl_event_log {
#define IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF	(100)
#define IWL_MAX_PLCP_ERR_THRESHOLD_MAX	(255)

enum iwl_reset {
	IWL_RF_RESET = 0,
	IWL_FW_RESET,
};

struct iwl_priv {

	/* ieee device used by generic ieee processing code */
@@ -1066,6 +1071,9 @@ struct iwl_priv {
	/* storing the jiffies when the plcp error rate is received */
	unsigned long plcp_jiffies;

	/* force reset */
	unsigned long last_force_reset_jiffies;

	/* we allocate array of iwl4965_channel_info for NIC's valid channels.
	 *    Access via channel # using indirect index array */
	struct iwl_channel_info *channel_info;	/* channel info array */
@@ -1087,7 +1095,6 @@ struct iwl_priv {
	unsigned long scan_start;
	unsigned long scan_pass_start;
	unsigned long scan_start_tsf;
	unsigned long last_internal_scan_jiffies;
	void *scan;
	int scan_bands;
	struct cfg80211_scan_request *scan_request;
+1 −1
Original line number Diff line number Diff line
@@ -689,7 +689,7 @@ void iwl_rx_statistics(struct iwl_priv *priv,
			 * Reset the RF radio due to the high plcp
			 * error rate
			 */
			iwl_force_rf_reset(priv);
			iwl_force_reset(priv, IWL_RF_RESET);
		}
	}

+0 −10
Original line number Diff line number Diff line
@@ -250,8 +250,6 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,

	if (!priv->is_internal_short_scan)
		priv->next_scan_jiffies = 0;
	else
		priv->last_internal_scan_jiffies = jiffies;

	IWL_DEBUG_INFO(priv, "Setting scan to off\n");

@@ -551,8 +549,6 @@ EXPORT_SYMBOL(iwl_mac_hw_scan);
 * internal short scan, this function should only been called while associated.
 * It will reset and tune the radio to prevent possible RF related problem
 */
#define IWL_DELAY_NEXT_INTERNAL_SCAN (HZ*1)

int iwl_internal_short_hw_scan(struct iwl_priv *priv)
{
	int ret = 0;
@@ -572,12 +568,6 @@ int iwl_internal_short_hw_scan(struct iwl_priv *priv)
		ret = -EAGAIN;
		goto out;
	}
	if (priv->last_internal_scan_jiffies &&
	    time_after(priv->last_internal_scan_jiffies +
		       IWL_DELAY_NEXT_INTERNAL_SCAN, jiffies)) {
		IWL_DEBUG_SCAN(priv, "internal scan rejected\n");
		goto out;
	}

	priv->scan_bands = 0;
	if (priv->band == IEEE80211_BAND_5GHZ)