Commit 52b0e7a6 authored by Juuso Oikarinen's avatar Juuso Oikarinen Committed by Luciano Coelho

wl1271: Add hardware recovery mechanism

There is some probability of hardware failures, which currently go largely
undetected. Attempt to recover from these failures by shutting down the
hardware, and requesting mac80211 to reconfigure it.
Signed-off-by: default avatarJuuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: default avatarTeemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
Signed-off-by: default avatarLuciano Coelho <luciano.coelho@nokia.com>
parent 52a2a375
...@@ -408,6 +408,9 @@ struct wl1271 { ...@@ -408,6 +408,9 @@ struct wl1271 {
/* The target interrupt mask */ /* The target interrupt mask */
struct work_struct irq_work; struct work_struct irq_work;
/* Hardware recovery work */
struct work_struct recovery_work;
/* The mbox event mask */ /* The mbox event mask */
u32 event_mask; u32 event_mask;
......
...@@ -94,6 +94,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, ...@@ -94,6 +94,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
status = le16_to_cpu(cmd->status); status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) { if (status != CMD_STATUS_SUCCESS) {
wl1271_error("command execute failure %d", status); wl1271_error("command execute failure %d", status);
ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -EIO; ret = -EIO;
} }
...@@ -182,8 +183,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) ...@@ -182,8 +183,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
do { do {
if (time_after(jiffies, timeout)) if (time_after(jiffies, timeout)) {
ieee80211_queue_work(wl->hw, &wl->recovery_work);
return -ETIMEDOUT; return -ETIMEDOUT;
}
msleep(1); msleep(1);
......
...@@ -235,6 +235,9 @@ static struct conf_drv_settings default_conf = { ...@@ -235,6 +235,9 @@ static struct conf_drv_settings default_conf = {
} }
}; };
static void __wl1271_op_remove_interface(struct wl1271 *wl);
static void wl1271_device_release(struct device *dev) static void wl1271_device_release(struct device *dev)
{ {
...@@ -612,6 +615,26 @@ static int wl1271_fetch_nvs(struct wl1271 *wl) ...@@ -612,6 +615,26 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
return ret; return ret;
} }
static void wl1271_recovery_work(struct work_struct *work)
{
struct wl1271 *wl =
container_of(work, struct wl1271, recovery_work);
mutex_lock(&wl->mutex);
if (wl->state != WL1271_STATE_ON)
goto out;
wl1271_info("Hardware recovery in progress.");
/* reboot the chipset */
__wl1271_op_remove_interface(wl);
ieee80211_restart_hw(wl->hw);
out:
mutex_unlock(&wl->mutex);
}
static void wl1271_fw_wakeup(struct wl1271 *wl) static void wl1271_fw_wakeup(struct wl1271 *wl)
{ {
u32 elp_reg; u32 elp_reg;
...@@ -635,6 +658,7 @@ static int wl1271_setup(struct wl1271 *wl) ...@@ -635,6 +658,7 @@ static int wl1271_setup(struct wl1271 *wl)
INIT_WORK(&wl->irq_work, wl1271_irq_work); INIT_WORK(&wl->irq_work, wl1271_irq_work);
INIT_WORK(&wl->tx_work, wl1271_tx_work); INIT_WORK(&wl->tx_work, wl1271_tx_work);
INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
return 0; return 0;
} }
...@@ -793,11 +817,11 @@ int wl1271_plt_stop(struct wl1271 *wl) ...@@ -793,11 +817,11 @@ int wl1271_plt_stop(struct wl1271 *wl)
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->recovery_work);
return ret; return ret;
} }
static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{ {
struct wl1271 *wl = hw->priv; struct wl1271 *wl = hw->priv;
...@@ -1046,6 +1070,8 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw, ...@@ -1046,6 +1070,8 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
WARN_ON(wl->vif != vif); WARN_ON(wl->vif != vif);
__wl1271_op_remove_interface(wl); __wl1271_op_remove_interface(wl);
mutex_unlock(&wl->mutex); mutex_unlock(&wl->mutex);
cancel_work_sync(&wl->recovery_work);
} }
static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
......
...@@ -99,6 +99,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake) ...@@ -99,6 +99,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
&compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
if (ret == 0) { if (ret == 0) {
wl1271_error("ELP wakeup timeout!"); wl1271_error("ELP wakeup timeout!");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
goto err; goto err;
} else if (ret < 0) { } else if (ret < 0) {
......
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