summaryrefslogtreecommitdiffstats
path: root/package/mac80211/patches/540-ath9k_hang_check.patch
blob: 85e03bc98c7de96a1c6c52429c48951c7046d0f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -428,6 +428,7 @@ int ath_beaconq_config(struct ath_softc 
 
 #define ATH_PAPRD_TIMEOUT	100 /* msecs */
 
+void ath_hw_check(struct work_struct *work);
 void ath_paprd_calibrate(struct work_struct *work);
 void ath_ani_calibrate(unsigned long data);
 
@@ -563,6 +564,7 @@ struct ath_softc {
 	spinlock_t sc_pm_lock;
 	struct mutex mutex;
 	struct work_struct paprd_work;
+	struct work_struct hw_check_work;
 	struct completion paprd_complete;
 
 	u32 intrstatus;
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -516,6 +516,25 @@ static void ath_node_detach(struct ath_s
 		ath_tx_node_cleanup(sc, an);
 }
 
+void ath_hw_check(struct work_struct *work)
+{
+	struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
+	int i;
+
+	ath9k_ps_wakeup(sc);
+
+	for (i = 0; i < 3; i++) {
+		if (ath9k_hw_check_alive(sc->sc_ah))
+			goto out;
+
+		msleep(1);
+	}
+	ath_reset(sc, false);
+
+out:
+	ath9k_ps_restore(sc);
+}
+
 void ath9k_tasklet(unsigned long data)
 {
 	struct ath_softc *sc = (struct ath_softc *)data;
@@ -527,13 +546,15 @@ void ath9k_tasklet(unsigned long data)
 
 	ath9k_ps_wakeup(sc);
 
-	if ((status & ATH9K_INT_FATAL) ||
-	    !ath9k_hw_check_alive(ah)) {
+	if (status & ATH9K_INT_FATAL) {
 		ath_reset(sc, false);
 		ath9k_ps_restore(sc);
 		return;
 	}
 
+	if (!ath9k_hw_check_alive(ah))
+		ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+
 	if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
 		rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
 			  ATH9K_INT_RXORN);
@@ -1254,6 +1275,7 @@ static void ath9k_stop(struct ieee80211_
 
 	cancel_delayed_work_sync(&sc->tx_complete_work);
 	cancel_work_sync(&sc->paprd_work);
+	cancel_work_sync(&sc->hw_check_work);
 
 	if (!sc->num_sec_wiphy) {
 		cancel_delayed_work_sync(&sc->wiphy_work);
@@ -1977,6 +1999,7 @@ static void ath9k_sw_scan_start(struct i
 	sc->sc_flags |= SC_OP_SCANNING;
 	del_timer_sync(&common->ani.timer);
 	cancel_work_sync(&sc->paprd_work);
+	cancel_work_sync(&sc->hw_check_work);
 	cancel_delayed_work_sync(&sc->tx_complete_work);
 	mutex_unlock(&sc->mutex);
 }
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -751,6 +751,7 @@ int ath9k_init_device(u16 devid, struct 
 			goto error_world;
 	}
 
+	INIT_WORK(&sc->hw_check_work, ath_hw_check);
 	INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
 	INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
 	INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);