diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 3 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/gpio.c | 7 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/hw.h | 11 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/init.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 6 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/mci.c | 254 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/mci.h | 118 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 5 |
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 | ||
8 | ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o | 9 | ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o |
9 | ath9k-$(CONFIG_ATH9K_PCI) += pci.o | 10 | ath9k-$(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 | ||
449 | int ath_init_btcoex_timer(struct ath_softc *sc); | 452 | int 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 | ||
208 | struct ath9k_hw_capabilities { | 209 | struct 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 | ||
423 | enum 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 | |||
422 | struct ath9k_beacon_state { | 433 | struct 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 | |||
20 | u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 }; | ||
21 | |||
22 | static struct ath_mci_profile_info* | ||
23 | ath_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 | |||
35 | static 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 | |||
71 | static 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 | |||
89 | void 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 | |||
101 | static 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 | |||
118 | static 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 | |||
184 | void 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 | |||
211 | void 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 | |||
81 | struct 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 | |||
94 | struct ath_mci_profile_status { | ||
95 | bool is_critical; | ||
96 | bool is_link; | ||
97 | u8 conn_handle; | ||
98 | }; | ||
99 | |||
100 | struct 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 | |||
113 | void ath_mci_flush_profile(struct ath_mci_profile *mci); | ||
114 | void ath_mci_process_profile(struct ath_softc *sc, | ||
115 | struct ath_mci_profile_info *info); | ||
116 | void 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 |