Commit ed6f9dc6 authored by Vladimir Kondratiev's avatar Vladimir Kondratiev Committed by John W. Linville

wil6210: fw error recovery

upon fw error interrupt - in STA mode, disconnect/cancel scan and
then reset FW/HW
added module param - no_fw_recovery which is false by default
Signed-off-by: default avatarVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 0fef1818
......@@ -265,6 +265,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
u16 chnl[4];
} __packed cmd;
uint i, n;
int rc;
if (wil->scan_request) {
wil_err(wil, "Already scanning\n");
......@@ -305,8 +306,13 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
request->channels[i]->center_freq);
}
return wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
rc = wmi_send(wil, WMI_START_SCAN_CMDID, &cmd, sizeof(cmd.cmd) +
cmd.cmd.num_channels * sizeof(cmd.cmd.channel_list[0]));
if (rc)
wil->scan_request = NULL;
return rc;
}
static int wil_cfg80211_connect(struct wiphy *wiphy,
......
......@@ -328,6 +328,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
if (isr & ISR_MISC_FW_ERROR) {
wil_notify_fw_error(wil);
isr &= ~ISR_MISC_FW_ERROR;
wil_fw_error_recovery(wil);
}
if (isr & ISR_MISC_MBOX_EVT) {
......
......@@ -21,6 +21,10 @@
#include "wil6210.h"
#include "txrx.h"
static bool no_fw_recovery;
module_param(no_fw_recovery, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_recovery, " disable FW error recovery");
/*
* Due to a hardware issue,
* one has to read/write to/from NIC in 32-bit chunks;
......@@ -144,6 +148,36 @@ static void wil_connect_timer_fn(ulong x)
schedule_work(&wil->disconnect_worker);
}
static void wil_fw_error_worker(struct work_struct *work)
{
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;
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_MONITOR:
wil_info(wil, "fw error recovery started...\n");
wil_reset(wil);
/* need to re-allocate Rx ring after reset */
wil_rx_init(wil);
break;
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_P2P_GO:
/* recovery in these modes is done by upper layers */
break;
default:
break;
}
}
static int wil_find_free_vring(struct wil6210_priv *wil)
{
int i;
......@@ -196,6 +230,7 @@ int wil_priv_init(struct wil6210_priv *wil)
INIT_WORK(&wil->connect_worker, wil_connect_worker);
INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
INIT_LIST_HEAD(&wil->pending_wmi_ev);
spin_lock_init(&wil->wmi_ev_lock);
......@@ -222,6 +257,7 @@ void wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
void wil_priv_deinit(struct wil6210_priv *wil)
{
cancel_work_sync(&wil->disconnect_worker);
cancel_work_sync(&wil->fw_error_worker);
wil6210_disconnect(wil, NULL);
wmi_event_flush(wil);
destroy_workqueue(wil->wmi_wq_conn);
......@@ -335,6 +371,13 @@ int wil_reset(struct wil6210_priv *wil)
napi_synchronize(&wil->napi_tx);
}
if (wil->scan_request) {
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
wil->scan_request);
cfg80211_scan_done(wil->scan_request, true);
wil->scan_request = NULL;
}
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL);
......@@ -363,6 +406,11 @@ int wil_reset(struct wil6210_priv *wil)
return rc;
}
void wil_fw_error_recovery(struct wil6210_priv *wil)
{
wil_dbg_misc(wil, "starting fw error recovery\n");
schedule_work(&wil->fw_error_worker);
}
void wil_link_on(struct wil6210_priv *wil)
{
......
......@@ -370,6 +370,7 @@ struct wil6210_priv {
struct workqueue_struct *wmi_wq_conn; /* for connect worker */
struct work_struct connect_worker;
struct work_struct disconnect_worker;
struct work_struct fw_error_worker; /* for FW error recovery */
struct timer_list connect_timer;
int pending_connect_cid;
struct list_head pending_wmi_ev;
......@@ -447,6 +448,7 @@ void wil_if_remove(struct wil6210_priv *wil);
int wil_priv_init(struct wil6210_priv *wil);
void wil_priv_deinit(struct wil6210_priv *wil);
int wil_reset(struct wil6210_priv *wil);
void wil_fw_error_recovery(struct wil6210_priv *wil);
void wil_link_on(struct wil6210_priv *wil);
void wil_link_off(struct wil6210_priv *wil);
int wil_up(struct wil6210_priv *wil);
......
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