aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRajkumar Manoharan <rmanohar@qca.qualcomm.com>2012-10-12 04:37:23 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-10-29 15:18:53 -0400
commitdb60428b1af11cf216bb0736b24b2cf0c7b54071 (patch)
tree74eb2e59e278d4f62ea8294b32f66ae9d0db1a00
parent50072ebca3d0aec8c5b8543e767d45c6626523af (diff)
ath9k: Add concurrent WLAN and BT tx support for MCI based chips
This feature enables both WLAN and BT can transmit simultaneously by setting WLAN and BT to equal priorities. Whenever both are transmitting, it might violate regulatory power limits. To avoid regulatory violation, WLAN tx power will be adjusted according to BT power index based on avaliability of BT scheduling message. If the combined power exceeds threshold, BT transmission will be held off. Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_mci.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.c60
-rw-r--r--drivers/net/wireless/ath/ath9k/btcoex.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/mci.c60
-rw-r--r--drivers/net/wireless/ath/ath9k/mci.h3
5 files changed, 110 insertions, 17 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
index 2a2d01889613..29282348eb4d 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h
@@ -196,7 +196,6 @@ enum mci_state_type {
196 MCI_STATE_SEND_WLAN_COEX_VERSION, 196 MCI_STATE_SEND_WLAN_COEX_VERSION,
197 MCI_STATE_SEND_VERSION_QUERY, 197 MCI_STATE_SEND_VERSION_QUERY,
198 MCI_STATE_SEND_STATUS_QUERY, 198 MCI_STATE_SEND_STATUS_QUERY,
199 MCI_STATE_SET_CONCUR_TX_PRI,
200 MCI_STATE_RECOVER_RX, 199 MCI_STATE_RECOVER_RX,
201 MCI_STATE_NEED_FTP_STOMP, 200 MCI_STATE_NEED_FTP_STOMP,
202 MCI_STATE_DEBUG, 201 MCI_STATE_DEBUG,
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.c b/drivers/net/wireless/ath/ath9k/btcoex.c
index 419e9a3f2fed..05d9be5be52e 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.c
+++ b/drivers/net/wireless/ath/ath9k/btcoex.c
@@ -218,27 +218,45 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
218 enum ath_stomp_type stomp_type) 218 enum ath_stomp_type stomp_type)
219{ 219{
220 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; 220 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
221 struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
222 u8 txprio_shift[] = { 24, 16, 16, 0 }; /* tx priority weight */
223 bool concur_tx = (mci_hw->concur_tx && btcoex_hw->tx_prio[stomp_type]);
224 const u32 *weight = ar9003_wlan_weights[stomp_type];
225 int i;
221 226
222 if (AR_SREV_9300_20_OR_LATER(ah)) { 227 if (!AR_SREV_9300_20_OR_LATER(ah)) {
223 const u32 *weight = ar9003_wlan_weights[stomp_type];
224 int i;
225
226 if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
227 if ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
228 btcoex_hw->mci.stomp_ftp)
229 stomp_type = ATH_BTCOEX_STOMP_LOW_FTP;
230 weight = mci_wlan_weights[stomp_type];
231 }
232
233 for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
234 btcoex_hw->bt_weight[i] = AR9300_BT_WGHT;
235 btcoex_hw->wlan_weight[i] = weight[i];
236 }
237 } else {
238 btcoex_hw->bt_coex_weights = 228 btcoex_hw->bt_coex_weights =
239 SM(bt_weight, AR_BTCOEX_BT_WGHT) | 229 SM(bt_weight, AR_BTCOEX_BT_WGHT) |
240 SM(wlan_weight, AR_BTCOEX_WL_WGHT); 230 SM(wlan_weight, AR_BTCOEX_WL_WGHT);
231 return;
232 }
233
234 if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
235 enum ath_stomp_type stype =
236 ((stomp_type == ATH_BTCOEX_STOMP_LOW) &&
237 btcoex_hw->mci.stomp_ftp) ?
238 ATH_BTCOEX_STOMP_LOW_FTP : stomp_type;
239 weight = mci_wlan_weights[stype];
241 } 240 }
241
242 for (i = 0; i < AR9300_NUM_WLAN_WEIGHTS; i++) {
243 btcoex_hw->bt_weight[i] = AR9300_BT_WGHT;
244 btcoex_hw->wlan_weight[i] = weight[i];
245 if (concur_tx && i) {
246 btcoex_hw->wlan_weight[i] &=
247 ~(0xff << txprio_shift[i-1]);
248 btcoex_hw->wlan_weight[i] |=
249 (btcoex_hw->tx_prio[stomp_type] <<
250 txprio_shift[i-1]);
251 }
252 }
253 /* Last WLAN weight has to be adjusted wrt tx priority */
254 if (concur_tx) {
255 btcoex_hw->wlan_weight[i-1] &= ~(0xff << txprio_shift[i-1]);
256 btcoex_hw->wlan_weight[i-1] |= (btcoex_hw->tx_prio[stomp_type]
257 << txprio_shift[i-1]);
258 }
259
242} 260}
243EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight); 261EXPORT_SYMBOL(ath9k_hw_btcoex_set_weight);
244 262
@@ -385,3 +403,13 @@ void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
385 } 403 }
386} 404}
387EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp); 405EXPORT_SYMBOL(ath9k_hw_btcoex_bt_stomp);
406
407void ath9k_hw_btcoex_set_concur_txprio(struct ath_hw *ah, u8 *stomp_txprio)
408{
409 struct ath_btcoex_hw *btcoex = &ah->btcoex_hw;
410 int i;
411
412 for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++)
413 btcoex->tx_prio[i] = stomp_txprio[i];
414}
415EXPORT_SYMBOL(ath9k_hw_btcoex_set_concur_txprio);
diff --git a/drivers/net/wireless/ath/ath9k/btcoex.h b/drivers/net/wireless/ath/ath9k/btcoex.h
index 385197ad79b0..a260fcb99d13 100644
--- a/drivers/net/wireless/ath/ath9k/btcoex.h
+++ b/drivers/net/wireless/ath/ath9k/btcoex.h
@@ -84,6 +84,7 @@ struct ath9k_hw_mci {
84 u8 bt_ver_minor; 84 u8 bt_ver_minor;
85 u8 bt_state; 85 u8 bt_state;
86 u8 stomp_ftp; 86 u8 stomp_ftp;
87 bool concur_tx;
87}; 88};
88 89
89struct ath_btcoex_hw { 90struct ath_btcoex_hw {
@@ -98,6 +99,7 @@ struct ath_btcoex_hw {
98 u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */ 99 u32 bt_coex_mode2; /* Register setting for AR_BT_COEX_MODE2 */
99 u32 bt_weight[AR9300_NUM_BT_WEIGHTS]; 100 u32 bt_weight[AR9300_NUM_BT_WEIGHTS];
100 u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS]; 101 u32 wlan_weight[AR9300_NUM_WLAN_WEIGHTS];
102 u8 tx_prio[ATH_BTCOEX_STOMP_MAX];
101}; 103};
102 104
103void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah); 105void ath9k_hw_btcoex_init_scheme(struct ath_hw *ah);
@@ -112,5 +114,6 @@ void ath9k_hw_btcoex_set_weight(struct ath_hw *ah,
112void ath9k_hw_btcoex_disable(struct ath_hw *ah); 114void ath9k_hw_btcoex_disable(struct ath_hw *ah);
113void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah, 115void ath9k_hw_btcoex_bt_stomp(struct ath_hw *ah,
114 enum ath_stomp_type stomp_type); 116 enum ath_stomp_type stomp_type);
117void ath9k_hw_btcoex_set_concur_txprio(struct ath_hw *ah, u8 *stomp_txprio);
115 118
116#endif 119#endif
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
index 1733a5ac3279..b37c8af6e02c 100644
--- a/drivers/net/wireless/ath/ath9k/mci.c
+++ b/drivers/net/wireless/ath/ath9k/mci.c
@@ -43,6 +43,7 @@ static bool ath_mci_add_profile(struct ath_common *common,
43 struct ath_mci_profile_info *info) 43 struct ath_mci_profile_info *info)
44{ 44{
45 struct ath_mci_profile_info *entry; 45 struct ath_mci_profile_info *entry;
46 u8 voice_priority[] = { 110, 110, 110, 112, 110, 110, 114, 116, 118 };
46 47
47 if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) && 48 if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) &&
48 (info->type == MCI_GPM_COEX_PROFILE_VOICE)) 49 (info->type == MCI_GPM_COEX_PROFILE_VOICE))
@@ -59,6 +60,12 @@ static bool ath_mci_add_profile(struct ath_common *common,
59 memcpy(entry, info, 10); 60 memcpy(entry, info, 10);
60 INC_PROF(mci, info); 61 INC_PROF(mci, info);
61 list_add_tail(&entry->list, &mci->info); 62 list_add_tail(&entry->list, &mci->info);
63 if (info->type == MCI_GPM_COEX_PROFILE_VOICE) {
64 if (info->voice_type < sizeof(voice_priority))
65 mci->voice_priority = voice_priority[info->voice_type];
66 else
67 mci->voice_priority = 110;
68 }
62 69
63 return true; 70 return true;
64} 71}
@@ -250,6 +257,57 @@ static void ath9k_mci_work(struct work_struct *work)
250 ath_mci_update_scheme(sc); 257 ath_mci_update_scheme(sc);
251} 258}
252 259
260static void ath_mci_update_stomp_txprio(u8 cur_txprio, u8 *stomp_prio)
261{
262 if (cur_txprio < stomp_prio[ATH_BTCOEX_STOMP_NONE])
263 stomp_prio[ATH_BTCOEX_STOMP_NONE] = cur_txprio;
264
265 if (cur_txprio > stomp_prio[ATH_BTCOEX_STOMP_ALL])
266 stomp_prio[ATH_BTCOEX_STOMP_ALL] = cur_txprio;
267
268 if ((cur_txprio > ATH_MCI_HI_PRIO) &&
269 (cur_txprio < stomp_prio[ATH_BTCOEX_STOMP_LOW]))
270 stomp_prio[ATH_BTCOEX_STOMP_LOW] = cur_txprio;
271}
272
273static void ath_mci_set_concur_txprio(struct ath_softc *sc)
274{
275 struct ath_btcoex *btcoex = &sc->btcoex;
276 struct ath_mci_profile *mci = &btcoex->mci;
277 u8 stomp_txprio[] = { 0, 0, 0, 0 }; /* all, low, none, low_ftp */
278
279 if (mci->num_mgmt) {
280 stomp_txprio[ATH_BTCOEX_STOMP_ALL] = ATH_MCI_INQUIRY_PRIO;
281 if (!mci->num_pan && !mci->num_other_acl)
282 stomp_txprio[ATH_BTCOEX_STOMP_NONE] =
283 ATH_MCI_INQUIRY_PRIO;
284 } else {
285 u8 prof_prio[] = { 50, 90, 94, 52 };/* RFCOMM, A2DP, HID, PAN */
286
287 stomp_txprio[ATH_BTCOEX_STOMP_LOW] =
288 stomp_txprio[ATH_BTCOEX_STOMP_NONE] = 0xff;
289
290 if (mci->num_sco)
291 ath_mci_update_stomp_txprio(mci->voice_priority,
292 stomp_txprio);
293 if (mci->num_other_acl)
294 ath_mci_update_stomp_txprio(prof_prio[0], stomp_txprio);
295 if (mci->num_a2dp)
296 ath_mci_update_stomp_txprio(prof_prio[1], stomp_txprio);
297 if (mci->num_hid)
298 ath_mci_update_stomp_txprio(prof_prio[2], stomp_txprio);
299 if (mci->num_pan)
300 ath_mci_update_stomp_txprio(prof_prio[3], stomp_txprio);
301
302 if (stomp_txprio[ATH_BTCOEX_STOMP_NONE] == 0xff)
303 stomp_txprio[ATH_BTCOEX_STOMP_NONE] = 0;
304
305 if (stomp_txprio[ATH_BTCOEX_STOMP_LOW] == 0xff)
306 stomp_txprio[ATH_BTCOEX_STOMP_LOW] = 0;
307 }
308 ath9k_hw_btcoex_set_concur_txprio(sc->sc_ah, stomp_txprio);
309}
310
253static u8 ath_mci_process_profile(struct ath_softc *sc, 311static u8 ath_mci_process_profile(struct ath_softc *sc,
254 struct ath_mci_profile_info *info) 312 struct ath_mci_profile_info *info)
255{ 313{
@@ -281,6 +339,7 @@ static u8 ath_mci_process_profile(struct ath_softc *sc,
281 } else 339 } else
282 ath_mci_del_profile(common, mci, entry); 340 ath_mci_del_profile(common, mci, entry);
283 341
342 ath_mci_set_concur_txprio(sc);
284 return 1; 343 return 1;
285} 344}
286 345
@@ -314,6 +373,7 @@ static u8 ath_mci_process_status(struct ath_softc *sc,
314 mci->num_mgmt++; 373 mci->num_mgmt++;
315 } while (++i < ATH_MCI_MAX_PROFILE); 374 } while (++i < ATH_MCI_MAX_PROFILE);
316 375
376 ath_mci_set_concur_txprio(sc);
317 if (old_num_mgmt != mci->num_mgmt) 377 if (old_num_mgmt != mci->num_mgmt)
318 return 1; 378 return 1;
319 379
diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h
index a3df314c1e70..e85a0e9506fa 100644
--- a/drivers/net/wireless/ath/ath9k/mci.h
+++ b/drivers/net/wireless/ath/ath9k/mci.h
@@ -32,6 +32,8 @@
32#define ATH_MCI_MAX_PROFILE (ATH_MCI_MAX_ACL_PROFILE +\ 32#define ATH_MCI_MAX_PROFILE (ATH_MCI_MAX_ACL_PROFILE +\
33 ATH_MCI_MAX_SCO_PROFILE) 33 ATH_MCI_MAX_SCO_PROFILE)
34 34
35#define ATH_MCI_INQUIRY_PRIO 62
36#define ATH_MCI_HI_PRIO 60
35#define ATH_MCI_NUM_BT_CHANNELS 79 37#define ATH_MCI_NUM_BT_CHANNELS 79
36 38
37#define MCI_GPM_SET_CHANNEL_BIT(_p_gpm, _bt_chan) \ 39#define MCI_GPM_SET_CHANNEL_BIT(_p_gpm, _bt_chan) \
@@ -131,6 +133,7 @@ struct ath_mci_profile {
131 u8 num_pan; 133 u8 num_pan;
132 u8 num_other_acl; 134 u8 num_other_acl;
133 u8 num_bdr; 135 u8 num_bdr;
136 u8 voice_priority;
134}; 137};
135 138
136struct ath_mci_buf { 139struct ath_mci_buf {