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, ...@@ -265,6 +265,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
u16 chnl[4]; u16 chnl[4];
} __packed cmd; } __packed cmd;
uint i, n; uint i, n;
int rc;
if (wil->scan_request) { if (wil->scan_request) {
wil_err(wil, "Already scanning\n"); wil_err(wil, "Already scanning\n");
...@@ -305,8 +306,13 @@ static int wil_cfg80211_scan(struct wiphy *wiphy, ...@@ -305,8 +306,13 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
request->channels[i]->center_freq); 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])); 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, static int wil_cfg80211_connect(struct wiphy *wiphy,
......
...@@ -328,6 +328,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie) ...@@ -328,6 +328,7 @@ static irqreturn_t wil6210_irq_misc_thread(int irq, void *cookie)
if (isr & ISR_MISC_FW_ERROR) { if (isr & ISR_MISC_FW_ERROR) {
wil_notify_fw_error(wil); wil_notify_fw_error(wil);
isr &= ~ISR_MISC_FW_ERROR; isr &= ~ISR_MISC_FW_ERROR;
wil_fw_error_recovery(wil);
} }
if (isr & ISR_MISC_MBOX_EVT) { if (isr & ISR_MISC_MBOX_EVT) {
......
...@@ -21,6 +21,10 @@ ...@@ -21,6 +21,10 @@
#include "wil6210.h" #include "wil6210.h"
#include "txrx.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, * Due to a hardware issue,
* one has to read/write to/from NIC in 32-bit chunks; * one has to read/write to/from NIC in 32-bit chunks;
...@@ -144,6 +148,36 @@ static void wil_connect_timer_fn(ulong x) ...@@ -144,6 +148,36 @@ static void wil_connect_timer_fn(ulong x)
schedule_work(&wil->disconnect_worker); 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) static int wil_find_free_vring(struct wil6210_priv *wil)
{ {
int i; int i;
...@@ -196,6 +230,7 @@ int wil_priv_init(struct wil6210_priv *wil) ...@@ -196,6 +230,7 @@ int wil_priv_init(struct wil6210_priv *wil)
INIT_WORK(&wil->connect_worker, wil_connect_worker); INIT_WORK(&wil->connect_worker, wil_connect_worker);
INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker); INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
INIT_WORK(&wil->wmi_event_worker, wmi_event_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); INIT_LIST_HEAD(&wil->pending_wmi_ev);
spin_lock_init(&wil->wmi_ev_lock); spin_lock_init(&wil->wmi_ev_lock);
...@@ -222,6 +257,7 @@ void wil6210_disconnect(struct wil6210_priv *wil, void *bssid) ...@@ -222,6 +257,7 @@ void wil6210_disconnect(struct wil6210_priv *wil, void *bssid)
void wil_priv_deinit(struct wil6210_priv *wil) void wil_priv_deinit(struct wil6210_priv *wil)
{ {
cancel_work_sync(&wil->disconnect_worker); cancel_work_sync(&wil->disconnect_worker);
cancel_work_sync(&wil->fw_error_worker);
wil6210_disconnect(wil, NULL); wil6210_disconnect(wil, NULL);
wmi_event_flush(wil); wmi_event_flush(wil);
destroy_workqueue(wil->wmi_wq_conn); destroy_workqueue(wil->wmi_wq_conn);
...@@ -335,6 +371,13 @@ int wil_reset(struct wil6210_priv *wil) ...@@ -335,6 +371,13 @@ int wil_reset(struct wil6210_priv *wil)
napi_synchronize(&wil->napi_tx); 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); cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL); wil6210_disconnect(wil, NULL);
...@@ -363,6 +406,11 @@ int wil_reset(struct wil6210_priv *wil) ...@@ -363,6 +406,11 @@ int wil_reset(struct wil6210_priv *wil)
return rc; 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) void wil_link_on(struct wil6210_priv *wil)
{ {
......
...@@ -370,6 +370,7 @@ struct wil6210_priv { ...@@ -370,6 +370,7 @@ struct wil6210_priv {
struct workqueue_struct *wmi_wq_conn; /* for connect worker */ struct workqueue_struct *wmi_wq_conn; /* for connect worker */
struct work_struct connect_worker; struct work_struct connect_worker;
struct work_struct disconnect_worker; struct work_struct disconnect_worker;
struct work_struct fw_error_worker; /* for FW error recovery */
struct timer_list connect_timer; struct timer_list connect_timer;
int pending_connect_cid; int pending_connect_cid;
struct list_head pending_wmi_ev; struct list_head pending_wmi_ev;
...@@ -447,6 +448,7 @@ void wil_if_remove(struct wil6210_priv *wil); ...@@ -447,6 +448,7 @@ void wil_if_remove(struct wil6210_priv *wil);
int wil_priv_init(struct wil6210_priv *wil); int wil_priv_init(struct wil6210_priv *wil);
void wil_priv_deinit(struct wil6210_priv *wil); void wil_priv_deinit(struct wil6210_priv *wil);
int wil_reset(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_on(struct wil6210_priv *wil);
void wil_link_off(struct wil6210_priv *wil); void wil_link_off(struct wil6210_priv *wil);
int wil_up(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