aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorRajkumar Manoharan <rmanohar@qca.qualcomm.com>2011-10-24 08:49:49 -0400
committerJohn W. Linville <linville@tuxdriver.com>2011-11-08 15:54:30 -0500
commit7dc181c273861c4d96991f59a4fdcda3a3eaccae (patch)
treed92c03f8e35868a2a29bf1f59d6797c233fce0a1 /drivers/net
parent38df2f07b7bc5309ebb159438b435d1f25f31e35 (diff)
ath9k: Add btcoex profile management support for AR9462
AR9462 chips have the capabilities to provoide bluetooth profile information. For non-AR9462 btcoex chips, the BT priority traffic was identified by periodically polling the respective registers and updated dutycycle, stomptype, etc. As AR9462 chip offers the BT profile informations, let us make use of that to update aggregation limit, dutycycle, stomptype and wieghtages. Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath.h1
-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
11 files changed, 403 insertions, 7 deletions
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index 908fdbc3e0ee..fe4bf4da255f 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -240,6 +240,7 @@ enum ATH_DEBUG {
240 ATH_DBG_BTCOEX = 0x00002000, 240 ATH_DBG_BTCOEX = 0x00002000,
241 ATH_DBG_WMI = 0x00004000, 241 ATH_DBG_WMI = 0x00004000,
242 ATH_DBG_BSTUCK = 0x00008000, 242 ATH_DBG_BSTUCK = 0x00008000,
243 ATH_DBG_MCI = 0x00010000,
243 ATH_DBG_ANY = 0xffffffff 244 ATH_DBG_ANY = 0xffffffff
244}; 245};
245 246
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