aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/mci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/mci.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/mci.c171
1 files changed, 170 insertions, 1 deletions
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
index ec2d7c807567..0dd2cbb52d65 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}
@@ -150,7 +157,7 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
150 * For single PAN/FTP profile, allocate 35% for BT 157 * For single PAN/FTP profile, allocate 35% for BT
151 * to improve WLAN throughput. 158 * to improve WLAN throughput.
152 */ 159 */
153 btcoex->duty_cycle = 35; 160 btcoex->duty_cycle = AR_SREV_9565(sc->sc_ah) ? 40 : 35;
154 btcoex->btcoex_period = 53; 161 btcoex->btcoex_period = 53;
155 ath_dbg(common, MCI, 162 ath_dbg(common, MCI,
156 "Single PAN/FTP bt period %d ms dutycycle %d\n", 163 "Single PAN/FTP bt period %d ms dutycycle %d\n",
@@ -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
@@ -600,3 +660,112 @@ void ath_mci_enable(struct ath_softc *sc)
600 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) 660 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
601 sc->sc_ah->imask |= ATH9K_INT_MCI; 661 sc->sc_ah->imask |= ATH9K_INT_MCI;
602} 662}
663
664void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all)
665{
666 struct ath_hw *ah = sc->sc_ah;
667 struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
668 struct ath9k_channel *chan = ah->curchan;
669 u32 channelmap[] = {0x00000000, 0xffff0000, 0xffffffff, 0x7fffffff};
670 int i;
671 s16 chan_start, chan_end;
672 u16 wlan_chan;
673
674 if (!chan || !IS_CHAN_2GHZ(chan))
675 return;
676
677 if (allow_all)
678 goto send_wlan_chan;
679
680 wlan_chan = chan->channel - 2402;
681
682 chan_start = wlan_chan - 10;
683 chan_end = wlan_chan + 10;
684
685 if (chan->chanmode == CHANNEL_G_HT40PLUS)
686 chan_end += 20;
687 else if (chan->chanmode == CHANNEL_G_HT40MINUS)
688 chan_start -= 20;
689
690 /* adjust side band */
691 chan_start -= 7;
692 chan_end += 7;
693
694 if (chan_start <= 0)
695 chan_start = 0;
696 if (chan_end >= ATH_MCI_NUM_BT_CHANNELS)
697 chan_end = ATH_MCI_NUM_BT_CHANNELS - 1;
698
699 ath_dbg(ath9k_hw_common(ah), MCI,
700 "WLAN current channel %d mask BT channel %d - %d\n",
701 wlan_chan, chan_start, chan_end);
702
703 for (i = chan_start; i < chan_end; i++)
704 MCI_GPM_CLR_CHANNEL_BIT(&channelmap, i);
705
706send_wlan_chan:
707 /* update and send wlan channels info to BT */
708 for (i = 0; i < 4; i++)
709 mci->wlan_channels[i] = channelmap[i];
710 ar9003_mci_send_wlan_channels(ah);
711 ar9003_mci_state(ah, MCI_STATE_SEND_VERSION_QUERY);
712}
713
714void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,
715 bool concur_tx)
716{
717 struct ath_hw *ah = sc->sc_ah;
718 struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
719 bool old_concur_tx = mci_hw->concur_tx;
720
721 if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX)) {
722 mci_hw->concur_tx = false;
723 return;
724 }
725
726 if (!IS_CHAN_2GHZ(ah->curchan))
727 return;
728
729 if (setchannel) {
730 struct ath9k_hw_cal_data *caldata = &sc->caldata;
731 if ((caldata->chanmode == CHANNEL_G_HT40PLUS) &&
732 (ah->curchan->channel > caldata->channel) &&
733 (ah->curchan->channel <= caldata->channel + 20))
734 return;
735 if ((caldata->chanmode == CHANNEL_G_HT40MINUS) &&
736 (ah->curchan->channel < caldata->channel) &&
737 (ah->curchan->channel >= caldata->channel - 20))
738 return;
739 mci_hw->concur_tx = false;
740 } else
741 mci_hw->concur_tx = concur_tx;
742
743 if (old_concur_tx != mci_hw->concur_tx)
744 ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false);
745}
746
747void ath9k_mci_update_rssi(struct ath_softc *sc)
748{
749 struct ath_hw *ah = sc->sc_ah;
750 struct ath_btcoex *btcoex = &sc->btcoex;
751 struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
752
753 if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX))
754 return;
755
756 if (ah->stats.avgbrssi >= 40) {
757 if (btcoex->rssi_count < 0)
758 btcoex->rssi_count = 0;
759 if (++btcoex->rssi_count >= ATH_MCI_CONCUR_TX_SWITCH) {
760 btcoex->rssi_count = 0;
761 ath9k_mci_set_txpower(sc, false, true);
762 }
763 } else {
764 if (btcoex->rssi_count > 0)
765 btcoex->rssi_count = 0;
766 if (--btcoex->rssi_count <= -ATH_MCI_CONCUR_TX_SWITCH) {
767 btcoex->rssi_count = 0;
768 ath9k_mci_set_txpower(sc, false, false);
769 }
770 }
771}