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

Commit 9285ff4f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "wil6210: manual FW error recovery mode"

parents db307878 3e8144eb
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -728,6 +728,8 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
		wil_print_bcon_data(bcon);
	}

	wil_set_recovery_state(wil, fw_recovery_idle);

	mutex_lock(&wil->mutex);

	__wil_down(wil);
@@ -775,6 +777,8 @@ static int wil_cfg80211_stop_ap(struct wiphy *wiphy,

	wil_dbg_misc(wil, "%s()\n", __func__);

	wil_set_recovery_state(wil, fw_recovery_idle);

	mutex_lock(&wil->mutex);

	rc = wmi_pcp_stop(wil);
+67 −0
Original line number Diff line number Diff line
@@ -1037,6 +1037,71 @@ static const struct file_operations fops_info = {
	.llseek		= seq_lseek,
};

/*---------recovery------------*/
/* mode = [manual|auto]
 * state = [idle|pending|running]
 */
static ssize_t wil_read_file_recovery(struct file *file, char __user *user_buf,
				      size_t count, loff_t *ppos)
{
	struct wil6210_priv *wil = file->private_data;
	char buf[80];
	int n;
	static const char * const sstate[] = {"idle", "pending", "running"};

	n = snprintf(buf, sizeof(buf), "mode = %s\nstate = %s\n",
		     no_fw_recovery ? "manual" : "auto",
		     sstate[wil->recovery_state]);

	n = min_t(int, n, sizeof(buf));

	return simple_read_from_buffer(user_buf, count, ppos,
				       buf, n);
}

static ssize_t wil_write_file_recovery(struct file *file,
				       const char __user *buf_,
				       size_t count, loff_t *ppos)
{
	struct wil6210_priv *wil = file->private_data;
	static const char run_command[] = "run";
	char buf[sizeof(run_command) + 1]; /* to detect "runx" */
	ssize_t rc;

	if (wil->recovery_state != fw_recovery_pending) {
		wil_err(wil, "No recovery pending\n");
		return -EINVAL;
	}

	if (*ppos != 0) {
		wil_err(wil, "Offset [%d]\n", (int)*ppos);
		return -EINVAL;
	}

	if (count > sizeof(buf)) {
		wil_err(wil, "Input too long, len = %d\n", (int)count);
		return -EINVAL;
	}

	rc = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, buf_, count);
	if (rc < 0)
		return rc;

	buf[rc] = '\0';
	if (0 == strcmp(buf, run_command))
		wil_set_recovery_state(wil, fw_recovery_running);
	else
		wil_err(wil, "Bad recovery command \"%s\"\n", buf);

	return rc;
}

static const struct file_operations fops_recovery = {
	.read = wil_read_file_recovery,
	.write = wil_write_file_recovery,
	.open  = simple_open,
};

/*---------Station matrix------------*/
static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
{
@@ -1148,6 +1213,7 @@ static const struct {
	{"freq",	S_IRUGO,		&fops_freq},
	{"link",	S_IRUGO,		&fops_link},
	{"info",	S_IRUGO,		&fops_info},
	{"recovery",	S_IRUGO | S_IWUSR,	&fops_recovery},
};

static void wil6210_debugfs_init_files(struct wil6210_priv *wil,
@@ -1190,6 +1256,7 @@ static const struct dbg_off dbg_wil_off[] = {
	WIL_FIELD(status,	S_IRUGO | S_IWUSR,	doff_ulong),
	WIL_FIELD(fw_version,	S_IRUGO,		doff_u32),
	WIL_FIELD(hw_version,	S_IRUGO,		doff_x32),
	WIL_FIELD(recovery_count, S_IRUGO,		doff_u32),
	{},
};

+38 −8
Original line number Diff line number Diff line
@@ -25,9 +25,9 @@
#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10

static bool no_fw_recovery;
bool no_fw_recovery;
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
MODULE_PARM_DESC(no_fw_recovery, " disable automatic FW error recovery");

static bool no_fw_load = true;
module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
@@ -191,17 +191,38 @@ static void wil_scan_timer_fn(ulong x)
	schedule_work(&wil->fw_error_worker);
}

static int wil_wait_for_recovery(struct wil6210_priv *wil)
{
	if (wait_event_interruptible(wil->wq, wil->recovery_state !=
				     fw_recovery_pending)) {
		wil_err(wil, "Interrupt, canceling recovery\n");
		return -ERESTARTSYS;
	}
	if (wil->recovery_state != fw_recovery_running) {
		wil_info(wil, "Recovery cancelled\n");
		return -EINTR;
	}
	wil_info(wil, "Proceed with recovery\n");
	return 0;
}

void wil_set_recovery_state(struct wil6210_priv *wil, int state)
{
	wil_dbg_misc(wil, "%s(%d -> %d)\n", __func__,
		     wil->recovery_state, state);

	wil->recovery_state = state;
	wake_up_interruptible(&wil->wq);
}

static void wil_fw_error_worker(struct work_struct *work)
{
	struct wil6210_priv *wil = container_of(work,
			struct wil6210_priv, fw_error_worker);
	struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
						fw_error_worker);
	struct wireless_dev *wdev = wil->wdev;

	wil_dbg_misc(wil, "fw error worker\n");

	if (no_fw_recovery)
		return;

	/* increment @recovery_count if less then WIL6210_FW_RECOVERY_TO
	 * passed since last recovery attempt
	 */
@@ -224,8 +245,13 @@ static void wil_fw_error_worker(struct work_struct *work)
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
	case NL80211_IFTYPE_MONITOR:
		wil_info(wil, "fw error recovery started (try %d)...\n",
		wil_info(wil, "fw error recovery requested (try %d)...\n",
			 wil->recovery_count);
		if (!no_fw_recovery)
			wil->recovery_state = fw_recovery_running;
		if (0 != wil_wait_for_recovery(wil))
			break;

		__wil_down(wil);
		__wil_up(wil);
		break;
@@ -302,6 +328,7 @@ int wil_priv_init(struct wil6210_priv *wil)

	INIT_LIST_HEAD(&wil->pending_wmi_ev);
	spin_lock_init(&wil->wmi_ev_lock);
	init_waitqueue_head(&wil->wq);

	wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
	if (!wil->wmi_wq)
@@ -331,6 +358,7 @@ void wil_priv_deinit(struct wil6210_priv *wil)
{
	wil_dbg_misc(wil, "%s()\n", __func__);

	wil_set_recovery_state(wil, fw_recovery_idle);
	del_timer_sync(&wil->scan_timer);
	cancel_work_sync(&wil->disconnect_worker);
	cancel_work_sync(&wil->fw_error_worker);
@@ -573,6 +601,7 @@ int wil_reset(struct wil6210_priv *wil)
void wil_fw_error_recovery(struct wil6210_priv *wil)
{
	wil_dbg_misc(wil, "starting fw error recovery\n");
	wil->recovery_state = fw_recovery_pending;
	schedule_work(&wil->fw_error_worker);
}

@@ -724,6 +753,7 @@ int wil_down(struct wil6210_priv *wil)

	wil_dbg_misc(wil, "%s()\n", __func__);

	wil_set_recovery_state(wil, fw_recovery_idle);
	mutex_lock(&wil->mutex);
	rc = __wil_down(wil);
	mutex_unlock(&wil->mutex);
+11 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/timex.h>
#include "wil_platform.h"

extern bool no_fw_recovery;

#define WIL_NAME "wil6210"
#define WIL_FW_NAME "wil6210.fw"
@@ -379,6 +380,12 @@ struct wil_sta_info {
	unsigned long tid_rx_stop_requested[BITS_TO_LONGS(WIL_STA_TID_NUM)];
};

enum {
	fw_recovery_idle = 0,
	fw_recovery_pending = 1,
	fw_recovery_running = 2,
};

struct wil6210_priv {
	struct pci_dev *pdev;
	int n_msi;
@@ -389,8 +396,10 @@ struct wil6210_priv {
	u32 hw_version;
	struct wil_board *board;
	u8 n_mids; /* number of additional MIDs as reported by FW */
	int recovery_count; /* num of FW recovery attempts in a short time */
	u32 recovery_count; /* num of FW recovery attempts in a short time */
	u32 recovery_state; /* FW recovery state machine */
	unsigned long last_fw_recovery; /* jiffies of last fw recovery */
	wait_queue_head_t wq; /* for all wait_event() use */
	/* profile */
	u32 monitor_flags;
	u32 secure_pcp; /* create secure PCP? */
@@ -507,6 +516,7 @@ void wil_priv_deinit(struct wil6210_priv *wil);
int wil_reset(struct wil6210_priv *wil);
void wil_set_itr_trsh(struct wil6210_priv *wil);
void wil_fw_error_recovery(struct wil6210_priv *wil);
void wil_set_recovery_state(struct wil6210_priv *wil, int state);
void wil_link_on(struct wil6210_priv *wil);
void wil_link_off(struct wil6210_priv *wil);
int wil_up(struct wil6210_priv *wil);
+1 −0
Original line number Diff line number Diff line
@@ -299,6 +299,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
{
	wil_dbg_wmi(wil, "WMI: got FW ready event\n");

	wil_set_recovery_state(wil, fw_recovery_idle);
	set_bit(wil_status_fwready, &wil->status);
	/* let the reset sequence continue */
	complete(&wil->wmi_ready);