aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/ath/ath6kl/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c17
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.c4
-rw-r--r--drivers/net/wireless/ath/ath6kl/core.h18
-rw-r--r--drivers/net/wireless/ath/ath6kl/debug.h1
-rw-r--r--drivers/net/wireless/ath/ath6kl/hif.c1
-rw-r--r--drivers/net/wireless/ath/ath6kl/init.c19
-rw-r--r--drivers/net/wireless/ath/ath6kl/recovery.c62
-rw-r--r--drivers/net/wireless/ath/ath6kl/sdio.c3
-rw-r--r--drivers/net/wireless/ath/ath6kl/txrx.c3
10 files changed, 126 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/Makefile b/drivers/net/wireless/ath/ath6kl/Makefile
index 8cae8886f17d..cab0ec0d5380 100644
--- a/drivers/net/wireless/ath/ath6kl/Makefile
+++ b/drivers/net/wireless/ath/ath6kl/Makefile
@@ -34,6 +34,7 @@ ath6kl_core-y += main.o
34ath6kl_core-y += txrx.o 34ath6kl_core-y += txrx.o
35ath6kl_core-y += wmi.o 35ath6kl_core-y += wmi.o
36ath6kl_core-y += core.o 36ath6kl_core-y += core.o
37ath6kl_core-y += recovery.o
37ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o 38ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
38 39
39obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o 40obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index b58878648d22..8cf146b5c57f 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -2503,14 +2503,23 @@ static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
2503{ 2503{
2504 struct ath6kl *ar = wiphy_priv(wiphy); 2504 struct ath6kl *ar = wiphy_priv(wiphy);
2505 2505
2506 ath6kl_recovery_suspend(ar);
2507
2506 return ath6kl_hif_suspend(ar, wow); 2508 return ath6kl_hif_suspend(ar, wow);
2507} 2509}
2508 2510
2509static int __ath6kl_cfg80211_resume(struct wiphy *wiphy) 2511static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
2510{ 2512{
2511 struct ath6kl *ar = wiphy_priv(wiphy); 2513 struct ath6kl *ar = wiphy_priv(wiphy);
2514 int err;
2515
2516 err = ath6kl_hif_resume(ar);
2517 if (err)
2518 return err;
2512 2519
2513 return ath6kl_hif_resume(ar); 2520 ar->fw_recovery.enable = true;
2521
2522 return 0;
2514} 2523}
2515 2524
2516/* 2525/*
@@ -3434,6 +3443,10 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
3434 clear_bit(CONNECTED, &vif->flags); 3443 clear_bit(CONNECTED, &vif->flags);
3435 clear_bit(CONNECT_PEND, &vif->flags); 3444 clear_bit(CONNECT_PEND, &vif->flags);
3436 3445
3446 /* Stop netdev queues, needed during recovery */
3447 netif_stop_queue(vif->ndev);
3448 netif_carrier_off(vif->ndev);
3449
3437 /* disable scanning */ 3450 /* disable scanning */
3438 if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF, 3451 if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
3439 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0) 3452 0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
@@ -3447,7 +3460,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
3447 struct ath6kl_vif *vif; 3460 struct ath6kl_vif *vif;
3448 3461
3449 vif = ath6kl_vif_first(ar); 3462 vif = ath6kl_vif_first(ar);
3450 if (!vif) { 3463 if (!vif && ar->state != ATH6KL_STATE_RECOVERY) {
3451 /* save the current power mode before enabling power save */ 3464 /* save the current power mode before enabling power save */
3452 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; 3465 ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
3453 3466
diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c
index 82c4dd2a960e..adcaa965486b 100644
--- a/drivers/net/wireless/ath/ath6kl/core.c
+++ b/drivers/net/wireless/ath/ath6kl/core.c
@@ -202,6 +202,8 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
202 ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", 202 ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
203 __func__, wdev->netdev->name, wdev->netdev, ar); 203 __func__, wdev->netdev->name, wdev->netdev, ar);
204 204
205 ath6kl_recovery_init(ar);
206
205 return ret; 207 return ret;
206 208
207err_rxbuf_cleanup: 209err_rxbuf_cleanup:
@@ -291,6 +293,8 @@ void ath6kl_core_cleanup(struct ath6kl *ar)
291{ 293{
292 ath6kl_hif_power_off(ar); 294 ath6kl_hif_power_off(ar);
293 295
296 ath6kl_recovery_cleanup(ar);
297
294 destroy_workqueue(ar->ath6kl_wq); 298 destroy_workqueue(ar->ath6kl_wq);
295 299
296 if (ar->htc_target) 300 if (ar->htc_target)
diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h
index 8b31b9a0f38f..c7dcdadd8b83 100644
--- a/drivers/net/wireless/ath/ath6kl/core.h
+++ b/drivers/net/wireless/ath/ath6kl/core.h
@@ -645,6 +645,12 @@ enum ath6kl_state {
645 ATH6KL_STATE_DEEPSLEEP, 645 ATH6KL_STATE_DEEPSLEEP,
646 ATH6KL_STATE_CUTPOWER, 646 ATH6KL_STATE_CUTPOWER,
647 ATH6KL_STATE_WOW, 647 ATH6KL_STATE_WOW,
648 ATH6KL_STATE_RECOVERY,
649};
650
651/* Fw error recovery */
652enum ath6kl_fw_err {
653 ATH6KL_FW_ASSERT,
648}; 654};
649 655
650struct ath6kl { 656struct ath6kl {
@@ -790,6 +796,12 @@ struct ath6kl {
790 796
791 bool wiphy_registered; 797 bool wiphy_registered;
792 798
799 struct ath6kl_fw_recovery {
800 bool enable;
801 struct work_struct recovery_work;
802 unsigned long err_reason;
803 } fw_recovery;
804
793#ifdef CONFIG_ATH6KL_DEBUG 805#ifdef CONFIG_ATH6KL_DEBUG
794 struct { 806 struct {
795 struct sk_buff_head fwlog_queue; 807 struct sk_buff_head fwlog_queue;
@@ -925,4 +937,10 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type);
925void ath6kl_core_cleanup(struct ath6kl *ar); 937void ath6kl_core_cleanup(struct ath6kl *ar);
926void ath6kl_core_destroy(struct ath6kl *ar); 938void ath6kl_core_destroy(struct ath6kl *ar);
927 939
940/* Fw error recovery */
941void ath6kl_init_hw_restart(struct ath6kl *ar);
942void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason);
943void ath6kl_recovery_init(struct ath6kl *ar);
944void ath6kl_recovery_cleanup(struct ath6kl *ar);
945void ath6kl_recovery_suspend(struct ath6kl *ar);
928#endif /* CORE_H */ 946#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath/ath6kl/debug.h b/drivers/net/wireless/ath/ath6kl/debug.h
index 49639d8266c2..f97cd4ead543 100644
--- a/drivers/net/wireless/ath/ath6kl/debug.h
+++ b/drivers/net/wireless/ath/ath6kl/debug.h
@@ -44,6 +44,7 @@ enum ATH6K_DEBUG_MASK {
44 ATH6KL_DBG_SUSPEND = BIT(20), 44 ATH6KL_DBG_SUSPEND = BIT(20),
45 ATH6KL_DBG_USB = BIT(21), 45 ATH6KL_DBG_USB = BIT(21),
46 ATH6KL_DBG_USB_BULK = BIT(22), 46 ATH6KL_DBG_USB_BULK = BIT(22),
47 ATH6KL_DBG_RECOVERY = BIT(23),
47 ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */ 48 ATH6KL_DBG_ANY = 0xffffffff /* enable all logs */
48}; 49};
49 50
diff --git a/drivers/net/wireless/ath/ath6kl/hif.c b/drivers/net/wireless/ath/ath6kl/hif.c
index 68ed6c2665b7..029914a22ea0 100644
--- a/drivers/net/wireless/ath/ath6kl/hif.c
+++ b/drivers/net/wireless/ath/ath6kl/hif.c
@@ -136,6 +136,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev)
136 136
137 ath6kl_hif_dump_fw_crash(dev->ar); 137 ath6kl_hif_dump_fw_crash(dev->ar);
138 ath6kl_read_fwlogs(dev->ar); 138 ath6kl_read_fwlogs(dev->ar);
139 ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT);
139 140
140 return ret; 141 return ret;
141} 142}
diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c
index be27ebec9052..301443c9f9ee 100644
--- a/drivers/net/wireless/ath/ath6kl/init.c
+++ b/drivers/net/wireless/ath/ath6kl/init.c
@@ -1695,6 +1695,25 @@ int ath6kl_init_hw_stop(struct ath6kl *ar)
1695 return 0; 1695 return 0;
1696} 1696}
1697 1697
1698void ath6kl_init_hw_restart(struct ath6kl *ar)
1699{
1700
1701 ar->state = ATH6KL_STATE_RECOVERY;
1702
1703 ath6kl_cfg80211_stop_all(ar);
1704
1705 if (__ath6kl_init_hw_stop(ar))
1706 return;
1707
1708 if (__ath6kl_init_hw_start(ar)) {
1709 ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n");
1710 return;
1711 }
1712
1713 ar->state = ATH6KL_STATE_ON;
1714 ar->fw_recovery.err_reason = 0;
1715}
1716
1698/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */ 1717/* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */
1699void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) 1718void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
1700{ 1719{
diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c
new file mode 100644
index 000000000000..c225fc4d3d56
--- /dev/null
+++ b/drivers/net/wireless/ath/ath6kl/recovery.c
@@ -0,0 +1,62 @@
1/*
2 * Copyright (c) 2012 Qualcomm Atheros, Inc.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "core.h"
18#include "cfg80211.h"
19#include "debug.h"
20
21static void ath6kl_recovery_work(struct work_struct *work)
22{
23 struct ath6kl *ar = container_of(work, struct ath6kl,
24 fw_recovery.recovery_work);
25
26 ath6kl_init_hw_restart(ar);
27}
28
29void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason)
30{
31 ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n",
32 reason);
33
34 set_bit(reason, &ar->fw_recovery.err_reason);
35
36 if (ar->fw_recovery.enable && ar->state != ATH6KL_STATE_RECOVERY)
37 queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work);
38}
39
40void ath6kl_recovery_init(struct ath6kl *ar)
41{
42 struct ath6kl_fw_recovery *recovery = &ar->fw_recovery;
43
44 recovery->enable = true;
45 INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work);
46}
47
48void ath6kl_recovery_cleanup(struct ath6kl *ar)
49{
50 ar->fw_recovery.enable = false;
51
52 cancel_work_sync(&ar->fw_recovery.recovery_work);
53}
54
55void ath6kl_recovery_suspend(struct ath6kl *ar)
56{
57 ath6kl_recovery_cleanup(ar);
58
59 /* Process pending fw error detection */
60 if (ar->fw_recovery.err_reason)
61 ath6kl_init_hw_restart(ar);
62}
diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c
index cc17fe02bdad..a72a4d02a4c8 100644
--- a/drivers/net/wireless/ath/ath6kl/sdio.c
+++ b/drivers/net/wireless/ath/ath6kl/sdio.c
@@ -931,6 +931,9 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
931 931
932 case ATH6KL_STATE_RESUMING: 932 case ATH6KL_STATE_RESUMING:
933 break; 933 break;
934
935 case ATH6KL_STATE_RECOVERY:
936 break;
934 } 937 }
935 938
936 ath6kl_cfg80211_resume(ar); 939 ath6kl_cfg80211_resume(ar);
diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c
index 740a488ef504..cbe1a9d89112 100644
--- a/drivers/net/wireless/ath/ath6kl/txrx.c
+++ b/drivers/net/wireless/ath/ath6kl/txrx.c
@@ -288,7 +288,8 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
288 int status = 0; 288 int status = 0;
289 struct ath6kl_cookie *cookie = NULL; 289 struct ath6kl_cookie *cookie = NULL;
290 290
291 if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) { 291 if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW) ||
292 ar->state == ATH6KL_STATE_RECOVERY) {
292 dev_kfree_skb(skb); 293 dev_kfree_skb(skb);
293 return -EACCES; 294 return -EACCES;
294 } 295 }