Commit 4cc53383 authored by Ido Yariv's avatar Ido Yariv Committed by Luciano Coelho

wlcore: Prevent interaction with HW after recovery is queued

When a function requests to recover, it would normally abort and will
not send any additional commands to the HW. However, other threads may
not be aware of the failure and could try to communicate with the HW
after a recovery was queued, but before the recovery work began.

Fix this by introducing an intermediate state which is set when recovery
is queued, and modify all state checks accordingly.
Signed-off-by: default avatarIdo Yariv <ido@wizery.com>
Signed-off-by: default avatarLuciano Coelho <luca@coelho.fi>
parent 9b1a0a77
......@@ -220,7 +220,7 @@ static ssize_t clear_fw_stats_write(struct file *file,
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF)
if (unlikely(wl->state != WLCORE_STATE_ON))
goto out;
ret = wl18xx_acx_clear_statistics(wl);
......
......@@ -59,6 +59,9 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
u16 status;
u16 poll_count = 0;
if (WARN_ON(unlikely(wl->state == WLCORE_STATE_RESTARTING)))
return -EIO;
cmd = buf;
cmd->id = cpu_to_le16(id);
cmd->status = 0;
......
......@@ -62,11 +62,14 @@ void wl1271_debugfs_update_stats(struct wl1271 *wl)
mutex_lock(&wl->mutex);
if (unlikely(wl->state != WLCORE_STATE_ON))
goto out;
ret = wl1271_ps_elp_wakeup(wl);
if (ret < 0)
goto out;
if (wl->state == WL1271_STATE_ON && !wl->plt &&
if (!wl->plt &&
time_after(jiffies, wl->stats.fw_stats_update +
msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {
wl1271_acx_statistics(wl, wl->stats.fw_stats);
......@@ -286,7 +289,7 @@ static ssize_t dynamic_ps_timeout_write(struct file *file,
wl->conf.conn.dynamic_ps_timeout = value;
if (wl->state == WL1271_STATE_OFF)
if (unlikely(wl->state != WLCORE_STATE_ON))
goto out;
ret = wl1271_ps_elp_wakeup(wl);
......@@ -353,7 +356,7 @@ static ssize_t forced_ps_write(struct file *file,
wl->conf.conn.forced_ps = value;
if (wl->state == WL1271_STATE_OFF)
if (unlikely(wl->state != WLCORE_STATE_ON))
goto out;
ret = wl1271_ps_elp_wakeup(wl);
......@@ -999,7 +1002,7 @@ static ssize_t sleep_auth_write(struct file *file,
wl->conf.conn.sta_sleep_auth = value;
if (wl->state == WL1271_STATE_OFF) {
if (unlikely(wl->state != WLCORE_STATE_ON)) {
/* this will show up on "read" in case we are off */
wl->sleep_auth = value;
goto out;
......@@ -1060,7 +1063,7 @@ static ssize_t dev_mem_read(struct file *file,
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) {
if (unlikely(wl->state != WLCORE_STATE_ON)) {
ret = -EFAULT;
goto skip_read;
}
......@@ -1145,7 +1148,7 @@ static ssize_t dev_mem_write(struct file *file, const char __user *user_buf,
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) {
if (unlikely(wl->state != WLCORE_STATE_ON)) {
ret = -EFAULT;
goto skip_write;
}
......
......@@ -64,7 +64,7 @@ static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr,
return -EIO;
ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed);
if (ret && wl->state != WL1271_STATE_OFF)
if (ret && wl->state != WLCORE_STATE_OFF)
set_bit(WL1271_FLAG_IO_FAILED, &wl->flags);
return ret;
......@@ -80,7 +80,7 @@ static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr,
return -EIO;
ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed);
if (ret && wl->state != WL1271_STATE_OFF)
if (ret && wl->state != WLCORE_STATE_OFF)
set_bit(WL1271_FLAG_IO_FAILED, &wl->flags);
return ret;
......
This diff is collapsed.
......@@ -44,7 +44,7 @@ void wl1271_elp_work(struct work_struct *work)
mutex_lock(&wl->mutex);
if (unlikely(wl->state == WL1271_STATE_OFF))
if (unlikely(wl->state != WLCORE_STATE_ON))
goto out;
/* our work might have been already cancelled */
......
......@@ -46,7 +46,7 @@ void wl1271_scan_complete_work(struct work_struct *work)
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF)
if (unlikely(wl->state != WLCORE_STATE_ON))
goto out;
if (wl->scan.state == WL1271_SCAN_STATE_IDLE)
......
......@@ -92,7 +92,7 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[])
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) {
if (unlikely(wl->state != WLCORE_STATE_ON)) {
ret = -EINVAL;
goto out;
}
......@@ -164,7 +164,7 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[])
mutex_lock(&wl->mutex);
if (wl->state == WL1271_STATE_OFF) {
if (unlikely(wl->state != WLCORE_STATE_ON)) {
ret = -EINVAL;
goto out;
}
......
......@@ -687,7 +687,7 @@ int wlcore_tx_work_locked(struct wl1271 *wl)
int bus_ret = 0;
u8 hlid;
if (unlikely(wl->state == WL1271_STATE_OFF))
if (unlikely(wl->state != WLCORE_STATE_ON))
return 0;
while ((skb = wl1271_skb_dequeue(wl, &hlid))) {
......
......@@ -153,7 +153,7 @@ struct wl1271 {
spinlock_t wl_lock;
enum wl1271_state state;
enum wlcore_state state;
enum wl12xx_fw_type fw_type;
bool plt;
enum plt_mode plt_mode;
......
......@@ -85,9 +85,10 @@
#define WL1271_AGGR_BUFFER_SIZE (5 * PAGE_SIZE)
enum wl1271_state {
WL1271_STATE_OFF,
WL1271_STATE_ON,
enum wlcore_state {
WLCORE_STATE_OFF,
WLCORE_STATE_RESTARTING,
WLCORE_STATE_ON,
};
enum wl12xx_fw_type {
......
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