aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r--drivers/net/wireless/ath/ath9k/Makefile1
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c7
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h11
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/mci.c254
-rw-r--r--drivers/net/wireless/ath/ath9k/mci.h118
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c5
10 files changed, 402 insertions, 7 deletions
diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile
index 36ed3c46fec6..49d3f25f509d 100644
--- a/drivers/net/wireless/ath/ath9k/Makefile
+++ b/drivers/net/wireless/ath/ath9k/Makefile
@@ -4,6 +4,7 @@ ath9k-y += beacon.o \
4 main.o \ 4 main.o \
5 recv.o \ 5 recv.o \
6 xmit.o \ 6 xmit.o \
7 mci.o \
7 8
8ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o 9ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
9ath9k-$(CONFIG_ATH9K_PCI) += pci.o 10ath9k-$(CONFIG_ATH9K_PCI) += pci.o
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 1c269f50822b..4415e89bd3d9 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -25,6 +25,7 @@
25 25
26#include "debug.h" 26#include "debug.h"
27#include "common.h" 27#include "common.h"
28#include "mci.h"
28 29
29/* 30/*
30 * Header for the ath9k.ko driver core *only* -- hw code nor any other driver 31 * Header for the ath9k.ko driver core *only* -- hw code nor any other driver
@@ -443,7 +444,9 @@ struct ath_btcoex {
443 u32 btcoex_no_stomp; /* in usec */ 444 u32 btcoex_no_stomp; /* in usec */
444 u32 btcoex_period; /* in usec */ 445 u32 btcoex_period; /* in usec */
445 u32 btscan_no_stomp; /* in usec */ 446 u32 btscan_no_stomp; /* in usec */
447 u32 duty_cycle;
446 struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */ 448 struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
449 struct ath_mci_profile mci;
447}; 450};
448 451
449int ath_init_btcoex_timer(struct ath_softc *sc); 452int ath_init_btcoex_timer(struct ath_softc *sc);
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 655576c8fdab..2c279dcaf4ba 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -189,8 +189,8 @@ static void ath_btcoex_period_timer(unsigned long data)
189 bool is_btscan; 189 bool is_btscan;
190 190
191 ath9k_ps_wakeup(sc); 191 ath9k_ps_wakeup(sc);
192 ath_detect_bt_priority(sc); 192 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
193 193 ath_detect_bt_priority(sc);
194 is_btscan = sc->sc_flags & SC_OP_BT_SCAN; 194 is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
195 195
196 spin_lock_bh(&btcoex->btcoex_lock); 196 spin_lock_bh(&btcoex->btcoex_lock);
@@ -212,8 +212,9 @@ static void ath_btcoex_period_timer(unsigned long data)
212 } 212 }
213 213
214 ath9k_ps_restore(sc); 214 ath9k_ps_restore(sc);
215 timer_period = btcoex->btcoex_period / 1000;
215 mod_timer(&btcoex->period_timer, jiffies + 216 mod_timer(&btcoex->period_timer, jiffies +
216 msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); 217 msecs_to_jiffies(timer_period));
217} 218}
218 219
219/* 220/*
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index e1dc084eac5b..96b8b9914da1 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2331,7 +2331,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
2331 ah->enabled_cals |= TX_IQ_ON_AGC_CAL; 2331 ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
2332 } 2332 }
2333 if (AR_SREV_9462(ah)) 2333 if (AR_SREV_9462(ah))
2334 pCap->hw_caps |= ATH9K_HW_CAP_RTT; 2334 pCap->hw_caps |= ATH9K_HW_CAP_RTT | ATH9K_HW_CAP_MCI;
2335 2335
2336 return 0; 2336 return 0;
2337} 2337}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index f389b3c93cf3..33e8f2f9d425 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -203,6 +203,7 @@ enum ath9k_hw_caps {
203 ATH9K_HW_CAP_5GHZ = BIT(14), 203 ATH9K_HW_CAP_5GHZ = BIT(14),
204 ATH9K_HW_CAP_APM = BIT(15), 204 ATH9K_HW_CAP_APM = BIT(15),
205 ATH9K_HW_CAP_RTT = BIT(16), 205 ATH9K_HW_CAP_RTT = BIT(16),
206 ATH9K_HW_CAP_MCI = BIT(17),
206}; 207};
207 208
208struct ath9k_hw_capabilities { 209struct ath9k_hw_capabilities {
@@ -419,6 +420,16 @@ enum ath9k_rx_qtype {
419 ATH9K_RX_QUEUE_MAX, 420 ATH9K_RX_QUEUE_MAX,
420}; 421};
421 422
423enum ath_mci_gpm_coex_profile_type {
424 MCI_GPM_COEX_PROFILE_UNKNOWN,
425 MCI_GPM_COEX_PROFILE_RFCOMM,
426 MCI_GPM_COEX_PROFILE_A2DP,
427 MCI_GPM_COEX_PROFILE_HID,
428 MCI_GPM_COEX_PROFILE_BNEP,
429 MCI_GPM_COEX_PROFILE_VOICE,
430 MCI_GPM_COEX_PROFILE_MAX
431};
432
422struct ath9k_beacon_state { 433struct ath9k_beacon_state {
423 u32 bs_nexttbtt; 434 u32 bs_nexttbtt;
424 u32 bs_nextdtim; 435 u32 bs_nextdtim;
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index af1b32549531..e8af5821a963 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -423,6 +423,8 @@ static int ath9k_init_btcoex(struct ath_softc *sc)
423 txq = sc->tx.txq_map[WME_AC_BE]; 423 txq = sc->tx.txq_map[WME_AC_BE];
424 ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); 424 ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
425 sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; 425 sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
426 sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
427 INIT_LIST_HEAD(&sc->btcoex.mci.info);
426 break; 428 break;
427 default: 429 default:
428 WARN_ON(1); 430 WARN_ON(1);
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 93fbe6f40898..e1e006d81f73 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1133,8 +1133,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
1133 1133
1134 if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) && 1134 if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
1135 !ah->btcoex_hw.enabled) { 1135 !ah->btcoex_hw.enabled) {
1136 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, 1136 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
1137 AR_STOMP_LOW_WLAN_WGHT); 1137 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
1138 AR_STOMP_LOW_WLAN_WGHT);
1138 ath9k_hw_btcoex_enable(ah); 1139 ath9k_hw_btcoex_enable(ah);
1139 1140
1140 if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) 1141 if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
@@ -1237,6 +1238,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
1237 ath9k_hw_btcoex_disable(ah); 1238 ath9k_hw_btcoex_disable(ah);
1238 if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) 1239 if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
1239 ath9k_btcoex_timer_pause(sc); 1240 ath9k_btcoex_timer_pause(sc);
1241 ath_mci_flush_profile(&sc->btcoex.mci);
1240 } 1242 }
1241 1243
1242 spin_lock_bh(&sc->sc_pcu_lock); 1244 spin_lock_bh(&sc->sc_pcu_lock);
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
new file mode 100644
index 000000000000..0fbb141bc302
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/mci.c
@@ -0,0 +1,254 @@
1/*
2 * Copyright (c) 2010-2011 Atheros Communications 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 "ath9k.h"
18#include "mci.h"
19
20u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 };
21
22static struct ath_mci_profile_info*
23ath_mci_find_profile(struct ath_mci_profile *mci,
24 struct ath_mci_profile_info *info)
25{
26 struct ath_mci_profile_info *entry;
27
28 list_for_each_entry(entry, &mci->info, list) {
29 if (entry->conn_handle == info->conn_handle)
30 break;
31 }
32 return entry;
33}
34
35static bool ath_mci_add_profile(struct ath_common *common,
36 struct ath_mci_profile *mci,
37 struct ath_mci_profile_info *info)
38{
39 struct ath_mci_profile_info *entry;
40
41 if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) &&
42 (info->type == MCI_GPM_COEX_PROFILE_VOICE)) {
43 ath_dbg(common, ATH_DBG_MCI,
44 "Too many SCO profile, failed to add new profile\n");
45 return false;
46 }
47
48 if (((NUM_PROF(mci) - mci->num_sco) == ATH_MCI_MAX_ACL_PROFILE) &&
49 (info->type != MCI_GPM_COEX_PROFILE_VOICE)) {
50 ath_dbg(common, ATH_DBG_MCI,
51 "Too many ACL profile, failed to add new profile\n");
52 return false;
53 }
54
55 entry = ath_mci_find_profile(mci, info);
56
57 if (entry)
58 memcpy(entry, info, 10);
59 else {
60 entry = kzalloc(sizeof(*entry), GFP_KERNEL);
61 if (!entry)
62 return false;
63
64 memcpy(entry, info, 10);
65 INC_PROF(mci, info);
66 list_add_tail(&info->list, &mci->info);
67 }
68 return true;
69}
70
71static void ath_mci_del_profile(struct ath_common *common,
72 struct ath_mci_profile *mci,
73 struct ath_mci_profile_info *info)
74{
75 struct ath_mci_profile_info *entry;
76
77 entry = ath_mci_find_profile(mci, info);
78
79 if (!entry) {
80 ath_dbg(common, ATH_DBG_MCI,
81 "Profile to be deleted not found\n");
82 return;
83 }
84 DEC_PROF(mci, entry);
85 list_del(&entry->list);
86 kfree(entry);
87}
88
89void ath_mci_flush_profile(struct ath_mci_profile *mci)
90{
91 struct ath_mci_profile_info *info, *tinfo;
92
93 list_for_each_entry_safe(info, tinfo, &mci->info, list) {
94 list_del(&info->list);
95 DEC_PROF(mci, info);
96 kfree(info);
97 }
98 mci->aggr_limit = 0;
99}
100
101static void ath_mci_adjust_aggr_limit(struct ath_btcoex *btcoex)
102{
103 struct ath_mci_profile *mci = &btcoex->mci;
104 u32 wlan_airtime = btcoex->btcoex_period *
105 (100 - btcoex->duty_cycle) / 100;
106
107 /*
108 * Scale: wlan_airtime is in ms, aggr_limit is in 0.25 ms.
109 * When wlan_airtime is less than 4ms, aggregation limit has to be
110 * adjusted half of wlan_airtime to ensure that the aggregation can fit
111 * without collision with BT traffic.
112 */
113 if ((wlan_airtime <= 4) &&
114 (!mci->aggr_limit || (mci->aggr_limit > (2 * wlan_airtime))))
115 mci->aggr_limit = 2 * wlan_airtime;
116}
117
118static void ath_mci_update_scheme(struct ath_softc *sc)
119{
120 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
121 struct ath_btcoex *btcoex = &sc->btcoex;
122 struct ath_mci_profile *mci = &btcoex->mci;
123 struct ath_mci_profile_info *info;
124 u32 num_profile = NUM_PROF(mci);
125
126 if (num_profile == 1) {
127 info = list_first_entry(&mci->info,
128 struct ath_mci_profile_info,
129 list);
130 if (mci->num_sco && info->T == 12) {
131 mci->aggr_limit = 8;
132 ath_dbg(common, ATH_DBG_MCI,
133 "Single SCO, aggregation limit 2 ms\n");
134 } else if ((info->type == MCI_GPM_COEX_PROFILE_BNEP) &&
135 !info->master) {
136 btcoex->btcoex_period = 60;
137 ath_dbg(common, ATH_DBG_MCI,
138 "Single slave PAN/FTP, bt period 60 ms\n");
139 } else if ((info->type == MCI_GPM_COEX_PROFILE_HID) &&
140 (info->T > 0 && info->T < 50) &&
141 (info->A > 1 || info->W > 1)) {
142 btcoex->duty_cycle = 30;
143 mci->aggr_limit = 8;
144 ath_dbg(common, ATH_DBG_MCI,
145 "Multiple attempt/timeout single HID "
146 "aggregation limit 2 ms dutycycle 30%%\n");
147 }
148 } else if ((num_profile == 2) && (mci->num_hid == 2)) {
149 btcoex->duty_cycle = 30;
150 mci->aggr_limit = 8;
151 ath_dbg(common, ATH_DBG_MCI,
152 "Two HIDs aggregation limit 2 ms dutycycle 30%%\n");
153 } else if (num_profile > 3) {
154 mci->aggr_limit = 6;
155 ath_dbg(common, ATH_DBG_MCI,
156 "Three or more profiles aggregation limit 1.5 ms\n");
157 }
158
159 if (IS_CHAN_2GHZ(sc->sc_ah->curchan)) {
160 if (IS_CHAN_HT(sc->sc_ah->curchan))
161 ath_mci_adjust_aggr_limit(btcoex);
162 else
163 btcoex->btcoex_period >>= 1;
164 }
165
166 ath9k_hw_btcoex_disable(sc->sc_ah);
167 ath9k_btcoex_timer_pause(sc);
168
169 if (IS_CHAN_5GHZ(sc->sc_ah->curchan))
170 return;
171
172 btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_MAX_DUTY_CYCLE : 0);
173 if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)
174 btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE;
175
176 btcoex->btcoex_period *= 1000;
177 btcoex->btcoex_no_stomp = btcoex->btcoex_period *
178 (100 - btcoex->duty_cycle) / 100;
179
180 ath9k_hw_btcoex_enable(sc->sc_ah);
181 ath9k_btcoex_timer_resume(sc);
182}
183
184void ath_mci_process_profile(struct ath_softc *sc,
185 struct ath_mci_profile_info *info)
186{
187 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
188 struct ath_btcoex *btcoex = &sc->btcoex;
189 struct ath_mci_profile *mci = &btcoex->mci;
190
191 if (info->start) {
192 if (!ath_mci_add_profile(common, mci, info))
193 return;
194 } else
195 ath_mci_del_profile(common, mci, info);
196
197 btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
198 mci->aggr_limit = mci->num_sco ? 6 : 0;
199 if (NUM_PROF(mci)) {
200 btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
201 btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
202 } else {
203 btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL :
204 ATH_BTCOEX_STOMP_LOW;
205 btcoex->duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
206 }
207
208 ath_mci_update_scheme(sc);
209}
210
211void ath_mci_process_status(struct ath_softc *sc,
212 struct ath_mci_profile_status *status)
213{
214 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
215 struct ath_btcoex *btcoex = &sc->btcoex;
216 struct ath_mci_profile *mci = &btcoex->mci;
217 struct ath_mci_profile_info info;
218 int i = 0, old_num_mgmt = mci->num_mgmt;
219
220 /* Link status type are not handled */
221 if (status->is_link) {
222 ath_dbg(common, ATH_DBG_MCI,
223 "Skip link type status update\n");
224 return;
225 }
226
227 memset(&info, 0, sizeof(struct ath_mci_profile_info));
228
229 info.conn_handle = status->conn_handle;
230 if (ath_mci_find_profile(mci, &info)) {
231 ath_dbg(common, ATH_DBG_MCI,
232 "Skip non link state update for existing profile %d\n",
233 status->conn_handle);
234 return;
235 }
236 if (status->conn_handle >= ATH_MCI_MAX_PROFILE) {
237 ath_dbg(common, ATH_DBG_MCI,
238 "Ignore too many non-link update\n");
239 return;
240 }
241 if (status->is_critical)
242 __set_bit(status->conn_handle, mci->status);
243 else
244 __clear_bit(status->conn_handle, mci->status);
245
246 mci->num_mgmt = 0;
247 do {
248 if (test_bit(i, mci->status))
249 mci->num_mgmt++;
250 } while (++i < ATH_MCI_MAX_PROFILE);
251
252 if (old_num_mgmt != mci->num_mgmt)
253 ath_mci_update_scheme(sc);
254}
diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h
new file mode 100644
index 000000000000..9590c61822d1
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/mci.h
@@ -0,0 +1,118 @@
1/*
2 * Copyright (c) 2010-2011 Atheros Communications 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#ifndef MCI_H
18#define MCI_H
19
20#define ATH_MCI_DEF_BT_PERIOD 40
21#define ATH_MCI_BDR_DUTY_CYCLE 20
22#define ATH_MCI_MAX_DUTY_CYCLE 90
23
24#define ATH_MCI_DEF_AGGR_LIMIT 6 /* in 0.24 ms */
25#define ATH_MCI_MAX_ACL_PROFILE 7
26#define ATH_MCI_MAX_SCO_PROFILE 1
27#define ATH_MCI_MAX_PROFILE (ATH_MCI_MAX_ACL_PROFILE +\
28 ATH_MCI_MAX_SCO_PROFILE)
29
30#define INC_PROF(_mci, _info) do { \
31 switch (_info->type) { \
32 case MCI_GPM_COEX_PROFILE_RFCOMM:\
33 _mci->num_other_acl++; \
34 break; \
35 case MCI_GPM_COEX_PROFILE_A2DP: \
36 _mci->num_a2dp++; \
37 if (!_info->edr) \
38 _mci->num_bdr++; \
39 break; \
40 case MCI_GPM_COEX_PROFILE_HID: \
41 _mci->num_hid++; \
42 break; \
43 case MCI_GPM_COEX_PROFILE_BNEP: \
44 _mci->num_pan++; \
45 break; \
46 case MCI_GPM_COEX_PROFILE_VOICE: \
47 _mci->num_sco++; \
48 break; \
49 default: \
50 break; \
51 } \
52 } while (0)
53
54#define DEC_PROF(_mci, _info) do { \
55 switch (_info->type) { \
56 case MCI_GPM_COEX_PROFILE_RFCOMM:\
57 _mci->num_other_acl--; \
58 break; \
59 case MCI_GPM_COEX_PROFILE_A2DP: \
60 _mci->num_a2dp--; \
61 if (!_info->edr) \
62 _mci->num_bdr--; \
63 break; \
64 case MCI_GPM_COEX_PROFILE_HID: \
65 _mci->num_hid--; \
66 break; \
67 case MCI_GPM_COEX_PROFILE_BNEP: \
68 _mci->num_pan--; \
69 break; \
70 case MCI_GPM_COEX_PROFILE_VOICE: \
71 _mci->num_sco--; \
72 break; \
73 default: \
74 break; \
75 } \
76 } while (0)
77
78#define NUM_PROF(_mci) (_mci->num_other_acl + _mci->num_a2dp + \
79 _mci->num_hid + _mci->num_pan + _mci->num_sco)
80
81struct ath_mci_profile_info {
82 u8 type;
83 u8 conn_handle;
84 bool start;
85 bool master;
86 bool edr;
87 u8 voice_type;
88 u16 T; /* Voice: Tvoice, HID: Tsniff, in slots */
89 u8 W; /* Voice: Wvoice, HID: Sniff timeout, in slots */
90 u8 A; /* HID: Sniff attempt, in slots */
91 struct list_head list;
92};
93
94struct ath_mci_profile_status {
95 bool is_critical;
96 bool is_link;
97 u8 conn_handle;
98};
99
100struct ath_mci_profile {
101 struct list_head info;
102 DECLARE_BITMAP(status, ATH_MCI_MAX_PROFILE);
103 u16 aggr_limit;
104 u8 num_mgmt;
105 u8 num_sco;
106 u8 num_a2dp;
107 u8 num_hid;
108 u8 num_pan;
109 u8 num_other_acl;
110 u8 num_bdr;
111};
112
113void ath_mci_flush_profile(struct ath_mci_profile *mci);
114void ath_mci_process_profile(struct ath_softc *sc,
115 struct ath_mci_profile_info *info);
116void ath_mci_process_status(struct ath_softc *sc,
117 struct ath_mci_profile_status *status);
118#endif
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 03b0a651a591..55d077e7135d 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -601,6 +601,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
601 struct sk_buff *skb; 601 struct sk_buff *skb;
602 struct ieee80211_tx_info *tx_info; 602 struct ieee80211_tx_info *tx_info;
603 struct ieee80211_tx_rate *rates; 603 struct ieee80211_tx_rate *rates;
604 struct ath_mci_profile *mci = &sc->btcoex.mci;
604 u32 max_4ms_framelen, frmlen; 605 u32 max_4ms_framelen, frmlen;
605 u16 aggr_limit, legacy = 0; 606 u16 aggr_limit, legacy = 0;
606 int i; 607 int i;
@@ -645,7 +646,9 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
645 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy) 646 if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
646 return 0; 647 return 0;
647 648
648 if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED) 649 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
650 aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4;
651 else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
649 aggr_limit = min((max_4ms_framelen * 3) / 8, 652 aggr_limit = min((max_4ms_framelen * 3) / 8,
650 (u32)ATH_AMPDU_LIMIT_MAX); 653 (u32)ATH_AMPDU_LIMIT_MAX);
651 else 654 else