diff options
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/btcoex.c | 214 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/btcoex.h | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 215 |
5 files changed, 218 insertions, 222 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index e8a630ccfd96..f001cc262660 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -458,6 +458,7 @@ struct ath_btcoex { | |||
458 | unsigned long bt_priority_time; | 458 | unsigned long bt_priority_time; |
459 | u32 btcoex_no_stomp; /* in usec */ | 459 | u32 btcoex_no_stomp; /* in usec */ |
460 | u32 btcoex_period; /* in usec */ | 460 | u32 btcoex_period; /* in usec */ |
461 | struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ | ||
461 | }; | 462 | }; |
462 | 463 | ||
463 | /********************/ | 464 | /********************/ |
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c index be699241ca75..6209a56f7a9a 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.c +++ b/drivers/net/wireless/ath/ath9k/btcoex.c | |||
@@ -43,144 +43,10 @@ bool ath_btcoex_supported(u16 subsysid) | |||
43 | return false; | 43 | return false; |
44 | } | 44 | } |
45 | 45 | ||
46 | static void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info, | 46 | void ath9k_hw_init_btcoex_hw_info(struct ath_hw *ah, int qnum) |
47 | u32 bt_weight, | ||
48 | u32 wlan_weight) | ||
49 | { | 47 | { |
50 | btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | | 48 | struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; |
51 | SM(wlan_weight, AR_BTCOEX_WL_WGHT); | ||
52 | } | ||
53 | |||
54 | void ath9k_hw_btcoex_init_weight(struct ath_hw *ah) | ||
55 | { | ||
56 | ath_btcoex_set_weight(&ah->btcoex_info, AR_BT_COEX_WGHT, | ||
57 | AR_STOMP_LOW_WLAN_WGHT); | ||
58 | } | ||
59 | |||
60 | /* | ||
61 | * Detects if there is any priority bt traffic | ||
62 | */ | ||
63 | static void ath_detect_bt_priority(struct ath_softc *sc) | ||
64 | { | ||
65 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
66 | struct ath_hw *ah = sc->sc_ah; | ||
67 | |||
68 | if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_info.btpriority_gpio)) | ||
69 | btcoex->bt_priority_cnt++; | ||
70 | |||
71 | if (time_after(jiffies, btcoex->bt_priority_time + | ||
72 | msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { | ||
73 | if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { | ||
74 | DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, | ||
75 | "BT priority traffic detected"); | ||
76 | sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; | ||
77 | } else { | ||
78 | sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; | ||
79 | } | ||
80 | |||
81 | btcoex->bt_priority_cnt = 0; | ||
82 | btcoex->bt_priority_time = jiffies; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * Configures appropriate weight based on stomp type. | ||
88 | */ | ||
89 | static void ath_btcoex_bt_stomp(struct ath_softc *sc, | ||
90 | struct ath_btcoex_info *btinfo, | ||
91 | int stomp_type) | ||
92 | { | ||
93 | |||
94 | switch (stomp_type) { | ||
95 | case ATH_BTCOEX_STOMP_ALL: | ||
96 | ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, | ||
97 | AR_STOMP_ALL_WLAN_WGHT); | ||
98 | break; | ||
99 | case ATH_BTCOEX_STOMP_LOW: | ||
100 | ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, | ||
101 | AR_STOMP_LOW_WLAN_WGHT); | ||
102 | break; | ||
103 | case ATH_BTCOEX_STOMP_NONE: | ||
104 | ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, | ||
105 | AR_STOMP_NONE_WLAN_WGHT); | ||
106 | break; | ||
107 | default: | ||
108 | DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); | ||
109 | break; | ||
110 | } | ||
111 | |||
112 | ath9k_hw_btcoex_enable(sc->sc_ah); | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * This is the master bt coex timer which runs for every | ||
117 | * 45ms, bt traffic will be given priority during 55% of this | ||
118 | * period while wlan gets remaining 45% | ||
119 | */ | ||
120 | |||
121 | static void ath_btcoex_period_timer(unsigned long data) | ||
122 | { | ||
123 | struct ath_softc *sc = (struct ath_softc *) data; | ||
124 | struct ath_hw *ah = sc->sc_ah; | ||
125 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
126 | struct ath_btcoex_info *btinfo = &ah->btcoex_info; | ||
127 | |||
128 | ath_detect_bt_priority(sc); | ||
129 | |||
130 | spin_lock_bh(&btcoex->btcoex_lock); | ||
131 | |||
132 | ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); | ||
133 | |||
134 | spin_unlock_bh(&btcoex->btcoex_lock); | ||
135 | |||
136 | if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { | ||
137 | if (btcoex->hw_timer_enabled) | ||
138 | ath_gen_timer_stop(ah, btinfo->no_stomp_timer); | ||
139 | |||
140 | ath_gen_timer_start(ah, | ||
141 | btinfo->no_stomp_timer, | ||
142 | (ath9k_hw_gettsf32(sc->sc_ah) + | ||
143 | btcoex->btcoex_no_stomp), | ||
144 | btcoex->btcoex_no_stomp * 10); | ||
145 | btcoex->hw_timer_enabled = true; | ||
146 | } | ||
147 | |||
148 | mod_timer(&btcoex->period_timer, jiffies + | ||
149 | msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * Generic tsf based hw timer which configures weight | ||
154 | * registers to time slice between wlan and bt traffic | ||
155 | */ | ||
156 | |||
157 | static void ath_btcoex_no_stomp_timer(void *arg) | ||
158 | { | ||
159 | struct ath_softc *sc = (struct ath_softc *)arg; | ||
160 | struct ath_hw *ah = sc->sc_ah; | ||
161 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
162 | struct ath_btcoex_info *btinfo = &ah->btcoex_info; | ||
163 | |||
164 | DPRINTF(ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); | ||
165 | |||
166 | spin_lock_bh(&btcoex->btcoex_lock); | ||
167 | |||
168 | if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) | ||
169 | ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); | ||
170 | else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) | ||
171 | ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); | ||
172 | |||
173 | spin_unlock_bh(&btcoex->btcoex_lock); | ||
174 | } | ||
175 | |||
176 | static int ath_init_btcoex_info(struct ath_hw *ah, | ||
177 | struct ath_btcoex_info *btcoex_info) | ||
178 | { | ||
179 | struct ath_btcoex *btcoex = &ah->ah_sc->btcoex; | ||
180 | u32 i; | 49 | u32 i; |
181 | int qnum; | ||
182 | |||
183 | qnum = ath_tx_get_qnum(ah->ah_sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); | ||
184 | 50 | ||
185 | btcoex_info->bt_coex_mode = | 51 | btcoex_info->bt_coex_mode = |
186 | (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) | | 52 | (btcoex_info->bt_coex_mode & AR_BT_QCU_THRESH) | |
@@ -201,31 +67,11 @@ static int ath_init_btcoex_info(struct ath_hw *ah, | |||
201 | 67 | ||
202 | btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; | 68 | btcoex_info->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; |
203 | 69 | ||
204 | btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; | ||
205 | |||
206 | btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * | ||
207 | btcoex->btcoex_period / 100; | ||
208 | |||
209 | for (i = 0; i < 32; i++) | 70 | for (i = 0; i < 32; i++) |
210 | ah->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; | 71 | ah->hw_gen_timers.gen_timer_index[(debruijn32 << i) >> 27] = i; |
211 | |||
212 | setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, | ||
213 | (unsigned long) ah->ah_sc); | ||
214 | |||
215 | btcoex_info->no_stomp_timer = ath_gen_timer_alloc(ah, | ||
216 | ath_btcoex_no_stomp_timer, | ||
217 | ath_btcoex_no_stomp_timer, | ||
218 | (void *)ah->ah_sc, AR_FIRST_NDP_TIMER); | ||
219 | |||
220 | if (btcoex_info->no_stomp_timer == NULL) | ||
221 | return -ENOMEM; | ||
222 | |||
223 | spin_lock_init(&btcoex->btcoex_lock); | ||
224 | |||
225 | return 0; | ||
226 | } | 72 | } |
227 | 73 | ||
228 | static void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) | 74 | void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) |
229 | { | 75 | { |
230 | struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; | 76 | struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; |
231 | 77 | ||
@@ -246,7 +92,7 @@ static void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah) | |||
246 | ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); | 92 | ath9k_hw_cfg_gpio_input(ah, btcoex_info->btactive_gpio); |
247 | } | 93 | } |
248 | 94 | ||
249 | static void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) | 95 | void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) |
250 | { | 96 | { |
251 | struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; | 97 | struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; |
252 | 98 | ||
@@ -271,21 +117,6 @@ static void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah) | |||
271 | ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio); | 117 | ath9k_hw_cfg_gpio_input(ah, btcoex_info->btpriority_gpio); |
272 | } | 118 | } |
273 | 119 | ||
274 | int ath9k_hw_btcoex_init(struct ath_hw *ah) | ||
275 | { | ||
276 | struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; | ||
277 | int ret = 0; | ||
278 | |||
279 | if (btcoex_info->btcoex_scheme == ATH_BTCOEX_CFG_2WIRE) | ||
280 | ath9k_hw_btcoex_init_2wire(ah); | ||
281 | else { | ||
282 | ath9k_hw_btcoex_init_3wire(ah); | ||
283 | ret = ath_init_btcoex_info(ah, btcoex_info); | ||
284 | } | ||
285 | |||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | void ath9k_hw_btcoex_enable(struct ath_hw *ah) | 120 | void ath9k_hw_btcoex_enable(struct ath_hw *ah) |
290 | { | 121 | { |
291 | struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; | 122 | struct ath_btcoex_info *btcoex_info = &ah->btcoex_info; |
@@ -336,40 +167,3 @@ void ath9k_hw_btcoex_disable(struct ath_hw *ah) | |||
336 | 167 | ||
337 | ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; | 168 | ah->ah_sc->sc_flags &= ~SC_OP_BTCOEX_ENABLED; |
338 | } | 169 | } |
339 | |||
340 | /* | ||
341 | * Pause btcoex timer and bt duty cycle timer | ||
342 | */ | ||
343 | void ath_btcoex_timer_pause(struct ath_softc *sc) | ||
344 | { | ||
345 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
346 | struct ath_hw *ah = sc->sc_ah; | ||
347 | |||
348 | del_timer_sync(&btcoex->period_timer); | ||
349 | |||
350 | if (btcoex->hw_timer_enabled) | ||
351 | ath_gen_timer_stop(ah, ah->btcoex_info.no_stomp_timer); | ||
352 | |||
353 | btcoex->hw_timer_enabled = false; | ||
354 | } | ||
355 | |||
356 | /* | ||
357 | * (Re)start btcoex timers | ||
358 | */ | ||
359 | void ath_btcoex_timer_resume(struct ath_softc *sc) | ||
360 | { | ||
361 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
362 | struct ath_hw *ah = sc->sc_ah; | ||
363 | |||
364 | DPRINTF(ah, ATH_DBG_BTCOEX, "Starting btcoex timers"); | ||
365 | |||
366 | /* make sure duty cycle timer is also stopped when resuming */ | ||
367 | if (btcoex->hw_timer_enabled) | ||
368 | ath_gen_timer_stop(sc->sc_ah, ah->btcoex_info.no_stomp_timer); | ||
369 | |||
370 | btcoex->bt_priority_cnt = 0; | ||
371 | btcoex->bt_priority_time = jiffies; | ||
372 | sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; | ||
373 | |||
374 | mod_timer(&btcoex->period_timer, jiffies); | ||
375 | } | ||
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h index 12e86b70d950..ed8d01d2f762 100644 --- a/drivers/net/wireless/ath/ath9k/btcoex.h +++ b/drivers/net/wireless/ath/ath9k/btcoex.h | |||
@@ -72,13 +72,14 @@ struct ath_btcoex_info { | |||
72 | u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */ | 72 | u32 bt_coex_mode; /* Register setting for AR_BT_COEX_MODE */ |
73 | u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */ | 73 | u32 bt_coex_weights; /* Register setting for AR_BT_COEX_WEIGHT */ |
74 | u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ | 74 | u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ |
75 | struct ath_gen_timer *no_stomp_timer; /*Timer for no BT stomping*/ | ||
76 | }; | 75 | }; |
77 | 76 | ||
78 | bool ath_btcoex_supported(u16 subsysid); | 77 | bool ath_btcoex_supported(u16 subsysid); |
79 | void ath9k_hw_btcoex_init_weight(struct ath_hw *ah); | 78 | void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah); |
80 | int ath9k_hw_btcoex_init(struct ath_hw *ah); | 79 | void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah); |
80 | void ath9k_hw_init_btcoex_hw_info(struct ath_hw *ah, int qnum); | ||
81 | void ath9k_hw_btcoex_enable(struct ath_hw *ah); | 81 | void ath9k_hw_btcoex_enable(struct ath_hw *ah); |
82 | void ath9k_hw_btcoex_disable(struct ath_hw *ah); | 82 | void ath9k_hw_btcoex_disable(struct ath_hw *ah); |
83 | 83 | ||
84 | |||
84 | #endif | 85 | #endif |
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index f2b3a601d6a9..b244225ca050 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h | |||
@@ -679,7 +679,4 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); | |||
679 | #define ATH_PCIE_CAP_LINK_L1 2 | 679 | #define ATH_PCIE_CAP_LINK_L1 2 |
680 | 680 | ||
681 | void ath_pcie_aspm_disable(struct ath_softc *sc); | 681 | void ath_pcie_aspm_disable(struct ath_softc *sc); |
682 | |||
683 | void ath_btcoex_timer_resume(struct ath_softc *sc); | ||
684 | void ath_btcoex_timer_pause(struct ath_softc *sc); | ||
685 | #endif | 682 | #endif |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 63e1f183b470..9ac1ee0638f0 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -1286,9 +1286,9 @@ void ath_detach(struct ath_softc *sc) | |||
1286 | if (ATH_TXQ_SETUP(sc, i)) | 1286 | if (ATH_TXQ_SETUP(sc, i)) |
1287 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); | 1287 | ath_tx_cleanupq(sc, &sc->tx.txq[i]); |
1288 | 1288 | ||
1289 | if ((ah->btcoex_info.no_stomp_timer) && | 1289 | if ((sc->btcoex.no_stomp_timer) && |
1290 | ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) | 1290 | ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) |
1291 | ath_gen_timer_free(ah, ah->btcoex_info.no_stomp_timer); | 1291 | ath_gen_timer_free(ah, sc->btcoex.no_stomp_timer); |
1292 | 1292 | ||
1293 | ath9k_hw_detach(ah); | 1293 | ath9k_hw_detach(ah); |
1294 | ath9k_exit_debug(ah); | 1294 | ath9k_exit_debug(ah); |
@@ -1307,6 +1307,158 @@ static int ath9k_reg_notifier(struct wiphy *wiphy, | |||
1307 | } | 1307 | } |
1308 | 1308 | ||
1309 | /* | 1309 | /* |
1310 | * Detects if there is any priority bt traffic | ||
1311 | */ | ||
1312 | static void ath_detect_bt_priority(struct ath_softc *sc) | ||
1313 | { | ||
1314 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
1315 | struct ath_hw *ah = sc->sc_ah; | ||
1316 | |||
1317 | if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_info.btpriority_gpio)) | ||
1318 | btcoex->bt_priority_cnt++; | ||
1319 | |||
1320 | if (time_after(jiffies, btcoex->bt_priority_time + | ||
1321 | msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { | ||
1322 | if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { | ||
1323 | DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, | ||
1324 | "BT priority traffic detected"); | ||
1325 | sc->sc_flags |= SC_OP_BT_PRIORITY_DETECTED; | ||
1326 | } else { | ||
1327 | sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; | ||
1328 | } | ||
1329 | |||
1330 | btcoex->bt_priority_cnt = 0; | ||
1331 | btcoex->bt_priority_time = jiffies; | ||
1332 | } | ||
1333 | } | ||
1334 | |||
1335 | static void ath_btcoex_set_weight(struct ath_btcoex_info *btcoex_info, | ||
1336 | u32 bt_weight, | ||
1337 | u32 wlan_weight) | ||
1338 | { | ||
1339 | btcoex_info->bt_coex_weights = SM(bt_weight, AR_BTCOEX_BT_WGHT) | | ||
1340 | SM(wlan_weight, AR_BTCOEX_WL_WGHT); | ||
1341 | } | ||
1342 | |||
1343 | static void ath9k_hw_btcoex_init_weight(struct ath_hw *ah) | ||
1344 | { | ||
1345 | ath_btcoex_set_weight(&ah->btcoex_info, AR_BT_COEX_WGHT, | ||
1346 | AR_STOMP_LOW_WLAN_WGHT); | ||
1347 | } | ||
1348 | |||
1349 | /* | ||
1350 | * Configures appropriate weight based on stomp type. | ||
1351 | */ | ||
1352 | static void ath_btcoex_bt_stomp(struct ath_softc *sc, | ||
1353 | struct ath_btcoex_info *btinfo, | ||
1354 | int stomp_type) | ||
1355 | { | ||
1356 | |||
1357 | switch (stomp_type) { | ||
1358 | case ATH_BTCOEX_STOMP_ALL: | ||
1359 | ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, | ||
1360 | AR_STOMP_ALL_WLAN_WGHT); | ||
1361 | break; | ||
1362 | case ATH_BTCOEX_STOMP_LOW: | ||
1363 | ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, | ||
1364 | AR_STOMP_LOW_WLAN_WGHT); | ||
1365 | break; | ||
1366 | case ATH_BTCOEX_STOMP_NONE: | ||
1367 | ath_btcoex_set_weight(btinfo, AR_BT_COEX_WGHT, | ||
1368 | AR_STOMP_NONE_WLAN_WGHT); | ||
1369 | break; | ||
1370 | default: | ||
1371 | DPRINTF(sc->sc_ah, ATH_DBG_BTCOEX, "Invalid Stomptype\n"); | ||
1372 | break; | ||
1373 | } | ||
1374 | |||
1375 | ath9k_hw_btcoex_enable(sc->sc_ah); | ||
1376 | } | ||
1377 | |||
1378 | /* | ||
1379 | * This is the master bt coex timer which runs for every | ||
1380 | * 45ms, bt traffic will be given priority during 55% of this | ||
1381 | * period while wlan gets remaining 45% | ||
1382 | */ | ||
1383 | static void ath_btcoex_period_timer(unsigned long data) | ||
1384 | { | ||
1385 | struct ath_softc *sc = (struct ath_softc *) data; | ||
1386 | struct ath_hw *ah = sc->sc_ah; | ||
1387 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
1388 | struct ath_btcoex_info *btinfo = &ah->btcoex_info; | ||
1389 | |||
1390 | ath_detect_bt_priority(sc); | ||
1391 | |||
1392 | spin_lock_bh(&btcoex->btcoex_lock); | ||
1393 | |||
1394 | ath_btcoex_bt_stomp(sc, btinfo, btinfo->bt_stomp_type); | ||
1395 | |||
1396 | spin_unlock_bh(&btcoex->btcoex_lock); | ||
1397 | |||
1398 | if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { | ||
1399 | if (btcoex->hw_timer_enabled) | ||
1400 | ath_gen_timer_stop(ah, btcoex->no_stomp_timer); | ||
1401 | |||
1402 | ath_gen_timer_start(ah, | ||
1403 | btcoex->no_stomp_timer, | ||
1404 | (ath9k_hw_gettsf32(ah) + | ||
1405 | btcoex->btcoex_no_stomp), | ||
1406 | btcoex->btcoex_no_stomp * 10); | ||
1407 | btcoex->hw_timer_enabled = true; | ||
1408 | } | ||
1409 | |||
1410 | mod_timer(&btcoex->period_timer, jiffies + | ||
1411 | msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); | ||
1412 | } | ||
1413 | |||
1414 | /* | ||
1415 | * Generic tsf based hw timer which configures weight | ||
1416 | * registers to time slice between wlan and bt traffic | ||
1417 | */ | ||
1418 | static void ath_btcoex_no_stomp_timer(void *arg) | ||
1419 | { | ||
1420 | struct ath_softc *sc = (struct ath_softc *)arg; | ||
1421 | struct ath_hw *ah = sc->sc_ah; | ||
1422 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
1423 | struct ath_btcoex_info *btinfo = &ah->btcoex_info; | ||
1424 | |||
1425 | DPRINTF(ah, ATH_DBG_BTCOEX, "no stomp timer running \n"); | ||
1426 | |||
1427 | spin_lock_bh(&btcoex->btcoex_lock); | ||
1428 | |||
1429 | if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_LOW) | ||
1430 | ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_NONE); | ||
1431 | else if (btinfo->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) | ||
1432 | ath_btcoex_bt_stomp(sc, btinfo, ATH_BTCOEX_STOMP_LOW); | ||
1433 | |||
1434 | spin_unlock_bh(&btcoex->btcoex_lock); | ||
1435 | } | ||
1436 | |||
1437 | static int ath_init_btcoex_timer(struct ath_softc *sc) | ||
1438 | { | ||
1439 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
1440 | |||
1441 | btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; | ||
1442 | btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * | ||
1443 | btcoex->btcoex_period / 100; | ||
1444 | |||
1445 | setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, | ||
1446 | (unsigned long) sc); | ||
1447 | |||
1448 | spin_lock_init(&btcoex->btcoex_lock); | ||
1449 | |||
1450 | btcoex->no_stomp_timer = ath_gen_timer_alloc(sc->sc_ah, | ||
1451 | ath_btcoex_no_stomp_timer, | ||
1452 | ath_btcoex_no_stomp_timer, | ||
1453 | (void *) sc, AR_FIRST_NDP_TIMER); | ||
1454 | |||
1455 | if (!btcoex->no_stomp_timer) | ||
1456 | return -ENOMEM; | ||
1457 | |||
1458 | return 0; | ||
1459 | } | ||
1460 | |||
1461 | /* | ||
1310 | * Initialize and fill ath_softc, ath_sofct is the | 1462 | * Initialize and fill ath_softc, ath_sofct is the |
1311 | * "Software Carrier" struct. Historically it has existed | 1463 | * "Software Carrier" struct. Historically it has existed |
1312 | * to allow the separation between hardware specific | 1464 | * to allow the separation between hardware specific |
@@ -1317,6 +1469,7 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) | |||
1317 | struct ath_hw *ah = NULL; | 1469 | struct ath_hw *ah = NULL; |
1318 | int r = 0, i; | 1470 | int r = 0, i; |
1319 | int csz = 0; | 1471 | int csz = 0; |
1472 | int qnum; | ||
1320 | 1473 | ||
1321 | /* XXX: hardware will not be ready until ath_open() being called */ | 1474 | /* XXX: hardware will not be ready until ath_open() being called */ |
1322 | sc->sc_flags |= SC_OP_INVALID; | 1475 | sc->sc_flags |= SC_OP_INVALID; |
@@ -1521,10 +1674,23 @@ static int ath_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid) | |||
1521 | ARRAY_SIZE(ath9k_5ghz_chantable); | 1674 | ARRAY_SIZE(ath9k_5ghz_chantable); |
1522 | } | 1675 | } |
1523 | 1676 | ||
1524 | if (ah->btcoex_info.btcoex_scheme != ATH_BTCOEX_CFG_NONE) { | 1677 | switch (ah->btcoex_info.btcoex_scheme) { |
1525 | r = ath9k_hw_btcoex_init(ah); | 1678 | case ATH_BTCOEX_CFG_NONE: |
1679 | break; | ||
1680 | case ATH_BTCOEX_CFG_2WIRE: | ||
1681 | ath9k_hw_btcoex_init_2wire(ah); | ||
1682 | break; | ||
1683 | case ATH_BTCOEX_CFG_3WIRE: | ||
1684 | ath9k_hw_btcoex_init_3wire(ah); | ||
1685 | r = ath_init_btcoex_timer(sc); | ||
1526 | if (r) | 1686 | if (r) |
1527 | goto bad2; | 1687 | goto bad2; |
1688 | qnum = ath_tx_get_qnum(sc, ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); | ||
1689 | ath9k_hw_init_btcoex_hw_info(ah, qnum); | ||
1690 | break; | ||
1691 | default: | ||
1692 | WARN_ON(1); | ||
1693 | break; | ||
1528 | } | 1694 | } |
1529 | 1695 | ||
1530 | return 0; | 1696 | return 0; |
@@ -1906,6 +2072,27 @@ void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
1906 | /* mac80211 callbacks */ | 2072 | /* mac80211 callbacks */ |
1907 | /**********************/ | 2073 | /**********************/ |
1908 | 2074 | ||
2075 | /* | ||
2076 | * (Re)start btcoex timers | ||
2077 | */ | ||
2078 | static void ath9k_btcoex_timer_resume(struct ath_softc *sc) | ||
2079 | { | ||
2080 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
2081 | struct ath_hw *ah = sc->sc_ah; | ||
2082 | |||
2083 | DPRINTF(ah, ATH_DBG_BTCOEX, "Starting btcoex timers"); | ||
2084 | |||
2085 | /* make sure duty cycle timer is also stopped when resuming */ | ||
2086 | if (btcoex->hw_timer_enabled) | ||
2087 | ath_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); | ||
2088 | |||
2089 | btcoex->bt_priority_cnt = 0; | ||
2090 | btcoex->bt_priority_time = jiffies; | ||
2091 | sc->sc_flags &= ~SC_OP_BT_PRIORITY_DETECTED; | ||
2092 | |||
2093 | mod_timer(&btcoex->period_timer, jiffies); | ||
2094 | } | ||
2095 | |||
1909 | static int ath9k_start(struct ieee80211_hw *hw) | 2096 | static int ath9k_start(struct ieee80211_hw *hw) |
1910 | { | 2097 | { |
1911 | struct ath_wiphy *aphy = hw->priv; | 2098 | struct ath_wiphy *aphy = hw->priv; |
@@ -2018,7 +2205,7 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
2018 | 2205 | ||
2019 | ath_pcie_aspm_disable(sc); | 2206 | ath_pcie_aspm_disable(sc); |
2020 | if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) | 2207 | if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) |
2021 | ath_btcoex_timer_resume(sc); | 2208 | ath9k_btcoex_timer_resume(sc); |
2022 | } | 2209 | } |
2023 | 2210 | ||
2024 | mutex_unlock: | 2211 | mutex_unlock: |
@@ -2126,6 +2313,22 @@ exit: | |||
2126 | return 0; | 2313 | return 0; |
2127 | } | 2314 | } |
2128 | 2315 | ||
2316 | /* | ||
2317 | * Pause btcoex timer and bt duty cycle timer | ||
2318 | */ | ||
2319 | static void ath9k_btcoex_timer_pause(struct ath_softc *sc) | ||
2320 | { | ||
2321 | struct ath_btcoex *btcoex = &sc->btcoex; | ||
2322 | struct ath_hw *ah = sc->sc_ah; | ||
2323 | |||
2324 | del_timer_sync(&btcoex->period_timer); | ||
2325 | |||
2326 | if (btcoex->hw_timer_enabled) | ||
2327 | ath_gen_timer_stop(ah, btcoex->no_stomp_timer); | ||
2328 | |||
2329 | btcoex->hw_timer_enabled = false; | ||
2330 | } | ||
2331 | |||
2129 | static void ath9k_stop(struct ieee80211_hw *hw) | 2332 | static void ath9k_stop(struct ieee80211_hw *hw) |
2130 | { | 2333 | { |
2131 | struct ath_wiphy *aphy = hw->priv; | 2334 | struct ath_wiphy *aphy = hw->priv; |
@@ -2158,7 +2361,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
2158 | if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) { | 2361 | if (sc->sc_flags & SC_OP_BTCOEX_ENABLED) { |
2159 | ath9k_hw_btcoex_disable(ah); | 2362 | ath9k_hw_btcoex_disable(ah); |
2160 | if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) | 2363 | if (ah->btcoex_info.btcoex_scheme == ATH_BTCOEX_CFG_3WIRE) |
2161 | ath_btcoex_timer_pause(sc); | 2364 | ath9k_btcoex_timer_pause(sc); |
2162 | } | 2365 | } |
2163 | 2366 | ||
2164 | /* make sure h/w will not generate any interrupt | 2367 | /* make sure h/w will not generate any interrupt |