2 * Copyright (c) 2010-2011 Atheros Communications Inc.
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.
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.
20 u8 ath_mci_duty_cycle
[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 };
22 static struct ath_mci_profile_info
*
23 ath_mci_find_profile(struct ath_mci_profile
*mci
,
24 struct ath_mci_profile_info
*info
)
26 struct ath_mci_profile_info
*entry
;
28 list_for_each_entry(entry
, &mci
->info
, list
) {
29 if (entry
->conn_handle
== info
->conn_handle
)
35 static bool ath_mci_add_profile(struct ath_common
*common
,
36 struct ath_mci_profile
*mci
,
37 struct ath_mci_profile_info
*info
)
39 struct ath_mci_profile_info
*entry
;
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");
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");
55 entry
= ath_mci_find_profile(mci
, info
);
58 memcpy(entry
, info
, 10);
60 entry
= kzalloc(sizeof(*entry
), GFP_KERNEL
);
64 memcpy(entry
, info
, 10);
66 list_add_tail(&info
->list
, &mci
->info
);
71 static void ath_mci_del_profile(struct ath_common
*common
,
72 struct ath_mci_profile
*mci
,
73 struct ath_mci_profile_info
*info
)
75 struct ath_mci_profile_info
*entry
;
77 entry
= ath_mci_find_profile(mci
, info
);
80 ath_dbg(common
, ATH_DBG_MCI
,
81 "Profile to be deleted not found\n");
85 list_del(&entry
->list
);
89 void ath_mci_flush_profile(struct ath_mci_profile
*mci
)
91 struct ath_mci_profile_info
*info
, *tinfo
;
93 list_for_each_entry_safe(info
, tinfo
, &mci
->info
, list
) {
94 list_del(&info
->list
);
101 static void ath_mci_adjust_aggr_limit(struct ath_btcoex
*btcoex
)
103 struct ath_mci_profile
*mci
= &btcoex
->mci
;
104 u32 wlan_airtime
= btcoex
->btcoex_period
*
105 (100 - btcoex
->duty_cycle
) / 100;
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.
113 if ((wlan_airtime
<= 4) &&
114 (!mci
->aggr_limit
|| (mci
->aggr_limit
> (2 * wlan_airtime
))))
115 mci
->aggr_limit
= 2 * wlan_airtime
;
118 static void ath_mci_update_scheme(struct ath_softc
*sc
)
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
);
126 if (num_profile
== 1) {
127 info
= list_first_entry(&mci
->info
,
128 struct ath_mci_profile_info
,
130 if (mci
->num_sco
&& info
->T
== 12) {
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
) &&
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;
144 ath_dbg(common
, ATH_DBG_MCI
,
145 "Multiple attempt/timeout single HID "
146 "aggregation limit 2 ms dutycycle 30%%\n");
148 } else if ((num_profile
== 2) && (mci
->num_hid
== 2)) {
149 btcoex
->duty_cycle
= 30;
151 ath_dbg(common
, ATH_DBG_MCI
,
152 "Two HIDs aggregation limit 2 ms dutycycle 30%%\n");
153 } else if (num_profile
> 3) {
155 ath_dbg(common
, ATH_DBG_MCI
,
156 "Three or more profiles aggregation limit 1.5 ms\n");
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
);
163 btcoex
->btcoex_period
>>= 1;
166 ath9k_hw_btcoex_disable(sc
->sc_ah
);
167 ath9k_btcoex_timer_pause(sc
);
169 if (IS_CHAN_5GHZ(sc
->sc_ah
->curchan
))
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
;
176 btcoex
->btcoex_period
*= 1000;
177 btcoex
->btcoex_no_stomp
= btcoex
->btcoex_period
*
178 (100 - btcoex
->duty_cycle
) / 100;
180 ath9k_hw_btcoex_enable(sc
->sc_ah
);
181 ath9k_btcoex_timer_resume(sc
);
184 void ath_mci_process_profile(struct ath_softc
*sc
,
185 struct ath_mci_profile_info
*info
)
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
;
192 if (!ath_mci_add_profile(common
, mci
, info
))
195 ath_mci_del_profile(common
, mci
, info
);
197 btcoex
->btcoex_period
= ATH_MCI_DEF_BT_PERIOD
;
198 mci
->aggr_limit
= mci
->num_sco
? 6 : 0;
200 btcoex
->bt_stomp_type
= ATH_BTCOEX_STOMP_LOW
;
201 btcoex
->duty_cycle
= ath_mci_duty_cycle
[NUM_PROF(mci
)];
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
;
208 ath_mci_update_scheme(sc
);
211 void ath_mci_process_status(struct ath_softc
*sc
,
212 struct ath_mci_profile_status
*status
)
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
;
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");
227 memset(&info
, 0, sizeof(struct ath_mci_profile_info
));
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
);
236 if (status
->conn_handle
>= ATH_MCI_MAX_PROFILE
) {
237 ath_dbg(common
, ATH_DBG_MCI
,
238 "Ignore too many non-link update\n");
241 if (status
->is_critical
)
242 __set_bit(status
->conn_handle
, mci
->status
);
244 __clear_bit(status
->conn_handle
, mci
->status
);
248 if (test_bit(i
, mci
->status
))
250 } while (++i
< ATH_MCI_MAX_PROFILE
);
252 if (old_num_mgmt
!= mci
->num_mgmt
)
253 ath_mci_update_scheme(sc
);