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

Commit afbdd69a authored by Wey-Yi Guy's avatar Wey-Yi Guy Committed by John W. Linville
Browse files

iwlwifi: add function to reset/tune radio if needed



Adding "radio reset" function to help reset and stabilize the radio.

During normal operation, sometime for unknown reason, radio encounter
problem and can not recover by itself; the best way to
recover from it is to reset and re-tune the radio. Currently, there is
no RF reset command available, but since radio will get reset when
switching channel, use internal hw scan request to force radio
reset and get back to normal operation state.

The internal hw scan will only perform passive scan on the first
available channel (not the channel being used) in associated state. The
request should be ignored if already performing scan operation or STA is
not in associated state.

Also include an "internal_scan" debugfs file to help trigger the
internal scan from user mode.

Signed-off-by: default avatarWey-Yi Guy <wey-yi.w.guy@intel.com>
Signed-off-by: default avatarReinette Chatre <reinette.chatre@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a13d276f
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -3343,6 +3343,30 @@ 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)
{
	if (test_bit(STATUS_EXIT_PENDING, &priv->status))
		return;

	if (!iwl_is_associated(priv)) {
		IWL_DEBUG_SCAN(priv, "force reset rejected: not associated\n");
		return;
	}
	/*
	 * There is no easy and better way to force reset the radio,
	 * the only known method is switching channel which will force to
	 * reset and tune the radio.
	 * Use internal short scan (single channel) operation to should
	 * achieve this objective.
	 * Driver should reset the radio when number of consecutive missed
	 * beacon, or any other uCode error condition detected.
	 */
	IWL_DEBUG_INFO(priv, "perform radio reset.\n");
	iwl_internal_short_hw_scan(priv);
	return;
}
EXPORT_SYMBOL(iwl_force_rf_reset);

#ifdef CONFIG_PM

int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+2 −0
Original line number Diff line number Diff line
@@ -494,6 +494,8 @@ void iwl_init_scan_params(struct iwl_priv *priv);
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);
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);
+1 −0
Original line number Diff line number Diff line
@@ -113,6 +113,7 @@ struct iwl_debugfs {
		struct dentry *file_ucode_tracing;
		struct dentry *file_fh_reg;
		struct dentry *file_missed_beacon;
		struct dentry *file_internal_scan;
	} dbgfs_debug_files;
	u32 sram_offset;
	u32 sram_len;
+24 −0
Original line number Diff line number Diff line
@@ -2174,6 +2174,27 @@ static ssize_t iwl_dbgfs_missed_beacon_write(struct file *file,
	return count;
}

static ssize_t iwl_dbgfs_internal_scan_write(struct file *file,
					 const char __user *user_buf,
					 size_t count, loff_t *ppos)
{
	struct iwl_priv *priv = file->private_data;
	char buf[8];
	int buf_size;
	int scan;

	memset(buf, 0, sizeof(buf));
	buf_size = min(count, sizeof(buf) -  1);
	if (copy_from_user(buf, user_buf, buf_size))
		return -EFAULT;
	if (sscanf(buf, "%d", &scan) != 1)
		return -EINVAL;

	iwl_internal_short_hw_scan(priv);

	return count;
}

DEBUGFS_READ_FILE_OPS(rx_statistics);
DEBUGFS_READ_FILE_OPS(tx_statistics);
DEBUGFS_READ_WRITE_FILE_OPS(traffic_log);
@@ -2192,6 +2213,7 @@ DEBUGFS_WRITE_FILE_OPS(csr);
DEBUGFS_READ_WRITE_FILE_OPS(ucode_tracing);
DEBUGFS_READ_FILE_OPS(fh_reg);
DEBUGFS_READ_WRITE_FILE_OPS(missed_beacon);
DEBUGFS_WRITE_FILE_OPS(internal_scan);

/*
 * Create the debugfs files and directories
@@ -2245,6 +2267,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
	DEBUGFS_ADD_FILE(csr, debug, S_IWUSR);
	DEBUGFS_ADD_FILE(fh_reg, debug, S_IRUSR);
	DEBUGFS_ADD_FILE(missed_beacon, debug, S_IWUSR);
	DEBUGFS_ADD_FILE(internal_scan, debug, S_IWUSR);
	if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
		DEBUGFS_ADD_FILE(ucode_rx_stats, debug, S_IRUSR);
		DEBUGFS_ADD_FILE(ucode_tx_stats, debug, S_IRUSR);
@@ -2306,6 +2329,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_csr);
	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_fh_reg);
	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_missed_beacon);
	DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.file_internal_scan);
	if ((priv->hw_rev & CSR_HW_REV_TYPE_MSK) != CSR_HW_REV_TYPE_3945) {
		DEBUGFS_REMOVE(priv->dbgfs->dbgfs_debug_files.
			file_ucode_rx_stats);
+1 −0
Original line number Diff line number Diff line
@@ -1080,6 +1080,7 @@ struct iwl_priv {
	void *scan;
	int scan_bands;
	struct cfg80211_scan_request *scan_request;
	bool is_internal_short_scan;
	u8 scan_tx_ant[IEEE80211_NUM_BANDS];
	u8 mgmt_tx_ant;

Loading