ath9k: Send WLAN channel info to BT
authorRajkumar Manoharan <rmanohar@qca.qualcomm.com>
Fri, 12 Oct 2012 08:37:22 +0000 (14:07 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 29 Oct 2012 19:18:52 +0000 (15:18 -0400)
WLAN updates channel bitmap when associated and disassociated. Channel
bitmap will reflect whare are the channels used or affected by WLAN and
BT should avoid using those. Not doing so, could affect BT traffic
as both WLAN and BT is operating on same channel.

Signed-off-by: Rajkumar Manoharan <rmanohar@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c
drivers/net/wireless/ath/ath9k/mci.h

index 2da62be..515e184 100644 (file)
@@ -1450,6 +1450,9 @@ static void ath9k_set_assoc_state(struct ath_softc *sc,
        sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
+       if (ath9k_hw_mci_is_enabled(sc->sc_ah))
+               ath9k_mci_update_wlan_channels(sc, false);
+
        ath_dbg(common, CONFIG,
                "Primary Station interface: %pM, BSSID: %pM\n",
                vif->addr, common->curbssid);
@@ -1506,6 +1509,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                        memset(common->curbssid, 0, ETH_ALEN);
                        common->curaid = 0;
                        ath9k_hw_write_associd(sc->sc_ah);
+                       if (ath9k_hw_mci_is_enabled(sc->sc_ah))
+                               ath9k_mci_update_wlan_channels(sc, true);
                }
        }
 
index ec2d7c8..1733a5a 100644 (file)
@@ -600,3 +600,53 @@ void ath_mci_enable(struct ath_softc *sc)
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
                sc->sc_ah->imask |= ATH9K_INT_MCI;
 }
+
+void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
+       struct ath9k_channel *chan = ah->curchan;
+       u32 channelmap[] = {0x00000000, 0xffff0000, 0xffffffff, 0x7fffffff};
+       int i;
+       s16 chan_start, chan_end;
+       u16 wlan_chan;
+
+       if (!chan || !IS_CHAN_2GHZ(chan))
+               return;
+
+       if (allow_all)
+               goto send_wlan_chan;
+
+       wlan_chan = chan->channel - 2402;
+
+       chan_start = wlan_chan - 10;
+       chan_end = wlan_chan + 10;
+
+       if (chan->chanmode == CHANNEL_G_HT40PLUS)
+               chan_end += 20;
+       else if (chan->chanmode == CHANNEL_G_HT40MINUS)
+               chan_start -= 20;
+
+       /* adjust side band */
+       chan_start -= 7;
+       chan_end += 7;
+
+       if (chan_start <= 0)
+               chan_start = 0;
+       if (chan_end >= ATH_MCI_NUM_BT_CHANNELS)
+               chan_end = ATH_MCI_NUM_BT_CHANNELS - 1;
+
+       ath_dbg(ath9k_hw_common(ah), MCI,
+               "WLAN current channel %d mask BT channel %d - %d\n",
+               wlan_chan, chan_start, chan_end);
+
+       for (i = chan_start; i < chan_end; i++)
+               MCI_GPM_CLR_CHANNEL_BIT(&channelmap, i);
+
+send_wlan_chan:
+       /* update and send wlan channels info to BT */
+       for (i = 0; i < 4; i++)
+               mci->wlan_channels[i] = channelmap[i];
+       ar9003_mci_send_wlan_channels(ah);
+       ar9003_mci_state(ah, MCI_STATE_SEND_VERSION_QUERY);
+}
index fc14eea..a3df314 100644 (file)
 #define ATH_MCI_MAX_PROFILE            (ATH_MCI_MAX_ACL_PROFILE +\
                                         ATH_MCI_MAX_SCO_PROFILE)
 
+#define ATH_MCI_NUM_BT_CHANNELS      79
+
+#define MCI_GPM_SET_CHANNEL_BIT(_p_gpm, _bt_chan)                        \
+       do {                                                              \
+               if (_bt_chan < ATH_MCI_NUM_BT_CHANNELS) {                 \
+                       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_CHANNEL_MAP + \
+                               (_bt_chan / 8)) |= (1 << (_bt_chan & 7)); \
+               }                                                         \
+       } while (0)
+
+#define MCI_GPM_CLR_CHANNEL_BIT(_p_gpm, _bt_chan)                        \
+       do {                                                              \
+               if (_bt_chan < ATH_MCI_NUM_BT_CHANNELS) {                 \
+                       *(((u8 *)(_p_gpm)) + MCI_GPM_COEX_B_CHANNEL_MAP + \
+                               (_bt_chan / 8)) &= ~(1 << (_bt_chan & 7));\
+               }                                                         \
+       } while (0)
+
 #define INC_PROF(_mci, _info) do {              \
                switch (_info->type) {           \
                case MCI_GPM_COEX_PROFILE_RFCOMM:\
@@ -133,10 +151,15 @@ void ath_mci_intr(struct ath_softc *sc);
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
 void ath_mci_enable(struct ath_softc *sc);
+void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all);
 #else
 static inline void ath_mci_enable(struct ath_softc *sc)
 {
 }
+static inline void ath9k_mci_update_wlan_channels(struct ath_softc *sc,
+                                                 bool allow_all)
+{
+}
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
 
 #endif /* MCI_H*/