aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/wl12xx
diff options
context:
space:
mode:
authorJuuso Oikarinen <juuso.oikarinen@nokia.com>2010-09-21 00:23:31 -0400
committerLuciano Coelho <luciano.coelho@nokia.com>2010-09-28 05:30:04 -0400
commit52b0e7a61fd4b67fe8efe295297d8549f052f786 (patch)
tree7d6ca32a8abe67790466aa1cd3dbca41ce4db81c /drivers/net/wireless/wl12xx
parent52a2a37550b604b3c3c7a044ff72d85b60165659 (diff)
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: 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>
Diffstat (limited to 'drivers/net/wireless/wl12xx')
-rw-r--r--drivers/net/wireless/wl12xx/wl1271.h3
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_cmd.c5
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_main.c28
-rw-r--r--drivers/net/wireless/wl12xx/wl1271_ps.c3
4 files changed, 36 insertions, 3 deletions
diff --git a/drivers/net/wireless/wl12xx/wl1271.h b/drivers/net/wireless/wl12xx/wl1271.h
index 272cff44ab53..3576c1cb067f 100644
--- a/drivers/net/wireless/wl12xx/wl1271.h
+++ b/drivers/net/wireless/wl12xx/wl1271.h
@@ -408,6 +408,9 @@ struct wl1271 {
408 /* The target interrupt mask */ 408 /* The target interrupt mask */
409 struct work_struct irq_work; 409 struct work_struct irq_work;
410 410
411 /* Hardware recovery work */
412 struct work_struct recovery_work;
413
411 /* The mbox event mask */ 414 /* The mbox event mask */
412 u32 event_mask; 415 u32 event_mask;
413 416
diff --git a/drivers/net/wireless/wl12xx/wl1271_cmd.c b/drivers/net/wireless/wl12xx/wl1271_cmd.c
index 06b14f2abf55..170b5a8bdabc 100644
--- a/drivers/net/wireless/wl12xx/wl1271_cmd.c
+++ b/drivers/net/wireless/wl12xx/wl1271_cmd.c
@@ -94,6 +94,7 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
94 status = le16_to_cpu(cmd->status); 94 status = le16_to_cpu(cmd->status);
95 if (status != CMD_STATUS_SUCCESS) { 95 if (status != CMD_STATUS_SUCCESS) {
96 wl1271_error("command execute failure %d", status); 96 wl1271_error("command execute failure %d", status);
97 ieee80211_queue_work(wl->hw, &wl->recovery_work);
97 ret = -EIO; 98 ret = -EIO;
98 } 99 }
99 100
@@ -182,8 +183,10 @@ static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
182 timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); 183 timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
183 184
184 do { 185 do {
185 if (time_after(jiffies, timeout)) 186 if (time_after(jiffies, timeout)) {
187 ieee80211_queue_work(wl->hw, &wl->recovery_work);
186 return -ETIMEDOUT; 188 return -ETIMEDOUT;
189 }
187 190
188 msleep(1); 191 msleep(1);
189 192
diff --git a/drivers/net/wireless/wl12xx/wl1271_main.c b/drivers/net/wireless/wl12xx/wl1271_main.c
index e7f096fb6212..fecb0c313a1d 100644
--- a/drivers/net/wireless/wl12xx/wl1271_main.c
+++ b/drivers/net/wireless/wl12xx/wl1271_main.c
@@ -235,6 +235,9 @@ static struct conf_drv_settings default_conf = {
235 } 235 }
236}; 236};
237 237
238static void __wl1271_op_remove_interface(struct wl1271 *wl);
239
240
238static void wl1271_device_release(struct device *dev) 241static void wl1271_device_release(struct device *dev)
239{ 242{
240 243
@@ -612,6 +615,26 @@ out:
612 return ret; 615 return ret;
613} 616}
614 617
618static void wl1271_recovery_work(struct work_struct *work)
619{
620 struct wl1271 *wl =
621 container_of(work, struct wl1271, recovery_work);
622
623 mutex_lock(&wl->mutex);
624
625 if (wl->state != WL1271_STATE_ON)
626 goto out;
627
628 wl1271_info("Hardware recovery in progress.");
629
630 /* reboot the chipset */
631 __wl1271_op_remove_interface(wl);
632 ieee80211_restart_hw(wl->hw);
633
634out:
635 mutex_unlock(&wl->mutex);
636}
637
615static void wl1271_fw_wakeup(struct wl1271 *wl) 638static void wl1271_fw_wakeup(struct wl1271 *wl)
616{ 639{
617 u32 elp_reg; 640 u32 elp_reg;
@@ -635,6 +658,7 @@ static int wl1271_setup(struct wl1271 *wl)
635 INIT_WORK(&wl->irq_work, wl1271_irq_work); 658 INIT_WORK(&wl->irq_work, wl1271_irq_work);
636 INIT_WORK(&wl->tx_work, wl1271_tx_work); 659 INIT_WORK(&wl->tx_work, wl1271_tx_work);
637 INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); 660 INIT_WORK(&wl->scan_complete_work, wl1271_scan_complete_work);
661 INIT_WORK(&wl->recovery_work, wl1271_recovery_work);
638 662
639 return 0; 663 return 0;
640} 664}
@@ -793,11 +817,11 @@ out:
793 mutex_unlock(&wl->mutex); 817 mutex_unlock(&wl->mutex);
794 818
795 cancel_work_sync(&wl->irq_work); 819 cancel_work_sync(&wl->irq_work);
820 cancel_work_sync(&wl->recovery_work);
796 821
797 return ret; 822 return ret;
798} 823}
799 824
800
801static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) 825static int wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
802{ 826{
803 struct wl1271 *wl = hw->priv; 827 struct wl1271 *wl = hw->priv;
@@ -1046,6 +1070,8 @@ static void wl1271_op_remove_interface(struct ieee80211_hw *hw,
1046 WARN_ON(wl->vif != vif); 1070 WARN_ON(wl->vif != vif);
1047 __wl1271_op_remove_interface(wl); 1071 __wl1271_op_remove_interface(wl);
1048 mutex_unlock(&wl->mutex); 1072 mutex_unlock(&wl->mutex);
1073
1074 cancel_work_sync(&wl->recovery_work);
1049} 1075}
1050 1076
1051static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters) 1077static void wl1271_configure_filters(struct wl1271 *wl, unsigned int filters)
diff --git a/drivers/net/wireless/wl12xx/wl1271_ps.c b/drivers/net/wireless/wl12xx/wl1271_ps.c
index 150dc674d8b4..e3c332e2f97c 100644
--- a/drivers/net/wireless/wl12xx/wl1271_ps.c
+++ b/drivers/net/wireless/wl12xx/wl1271_ps.c
@@ -64,7 +64,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
64 test_bit(WL1271_FLAG_IDLE, &wl->flags)) { 64 test_bit(WL1271_FLAG_IDLE, &wl->flags)) {
65 cancel_delayed_work(&wl->elp_work); 65 cancel_delayed_work(&wl->elp_work);
66 ieee80211_queue_delayed_work(wl->hw, &wl->elp_work, 66 ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
67 msecs_to_jiffies(ELP_ENTRY_DELAY)); 67 msecs_to_jiffies(ELP_ENTRY_DELAY));
68 } 68 }
69} 69}
70 70
@@ -99,6 +99,7 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl, bool chip_awake)
99 &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); 99 &compl, msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT));
100 if (ret == 0) { 100 if (ret == 0) {
101 wl1271_error("ELP wakeup timeout!"); 101 wl1271_error("ELP wakeup timeout!");
102 ieee80211_queue_work(wl->hw, &wl->recovery_work);
102 ret = -ETIMEDOUT; 103 ret = -ETIMEDOUT;
103 goto err; 104 goto err;
104 } else if (ret < 0) { 105 } else if (ret < 0) {