Skip to content

Commit

Permalink
wl1271: Add hardware recovery mechanism
Browse files Browse the repository at this point in the history
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: Juuso Oikarinen <juuso.oikarinen@nokia.com>
Reviewed-by: Teemu Paasikivi <ext-teemu.3.paasikivi@nokia.com>
Signed-off-by: Luciano Coelho <luciano.coelho@nokia.com>
  • Loading branch information
Juuso Oikarinen authored and Luciano Coelho committed Sep 28, 2010
1 parent 52a2a37 commit 52b0e7a
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 3 deletions.
3 changes: 3 additions & 0 deletions drivers/net/wireless/wl12xx/wl1271.h
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,9 @@ struct wl1271 {
/* The target interrupt mask */
struct work_struct irq_work;

/* Hardware recovery work */
struct work_struct recovery_work;

/* The mbox event mask */
u32 event_mask;

Expand Down
5 changes: 4 additions & 1 deletion drivers/net/wireless/wl12xx/wl1271_cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) {
wl1271_error("command execute failure %d", status);
ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -EIO;
}

Expand Down Expand Up @@ -182,8 +183,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);

do {
if (time_after(jiffies, timeout))
if (time_after(jiffies, timeout)) {
ieee80211_queue_work(wl->hw, &wl->recovery_work);
return -ETIMEDOUT;
}

msleep(1);

Expand Down
28 changes: 27 additions & 1 deletion drivers/net/wireless/wl12xx/wl1271_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{

Expand Down Expand Up @@ -612,6 +615,26 @@ static int wl1271_fetch_nvs(struct wl1271 *wl)
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)
{
u32 elp_reg;
Expand All @@ -635,6 +658,7 @@ static int wl1271_setup(struct wl1271 *wl)
INIT_WORK(&wl->irq_work, wl1271_irq_work);
INIT_WORK(&wl->tx_work, wl1271_tx_work);
INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
INIT_WORK(&wl->recovery_work, wl1271_recovery_work);

return 0;
}
Expand Down Expand Up @@ -793,11 +817,11 @@ int wl1271_plt_stop(struct wl1271 *wl)
mutex_unlock(&wl->mutex);

cancel_work_sync(&wl->irq_work);
cancel_work_sync(&wl->recovery_work);

return ret;
}


static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct wl1271 *wl = hw->priv;
Expand Down Expand Up @@ -1046,6 +1070,8 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
WARN_ON(wl->vif != vif);
__wl1271_op_remove_interface(wl);
mutex_unlock(&wl->mutex);

cancel_work_sync(&wl->recovery_work);
}

static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
Expand Down
3 changes: 2 additions & 1 deletion drivers/net/wireless/wl12xx/wl1271_ps.c
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
test_bit(WL1271_FLAG_IDLE, &wl->flags)) {
cancel_delayed_work(&wl->elp_work);
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
msecs_to_jiffies(ELP_ENTRY_DELAY));
msecs_to_jiffies(ELP_ENTRY_DELAY));
}
}

Expand Down Expand Up @@ -99,6 +99,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
&compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
if (ret == 0) {
wl1271_error("ELP wakeup timeout!");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -ETIMEDOUT;
goto err;
} else if (ret < 0) {
Expand Down

0 comments on commit 52b0e7a

Please sign in to comment.