Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright (c) 2010-2011 Atheros Communications Inc.
0003  *
0004  * Permission to use, copy, modify, and/or distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 
0017 #include <linux/dma-mapping.h>
0018 #include <linux/slab.h>
0019 
0020 #include "ath9k.h"
0021 #include "mci.h"
0022 
0023 static const u8 ath_mci_duty_cycle[] = { 55, 50, 60, 70, 80, 85, 90, 95, 98 };
0024 
0025 static struct ath_mci_profile_info*
0026 ath_mci_find_profile(struct ath_mci_profile *mci,
0027              struct ath_mci_profile_info *info)
0028 {
0029     struct ath_mci_profile_info *entry;
0030 
0031     if (list_empty(&mci->info))
0032         return NULL;
0033 
0034     list_for_each_entry(entry, &mci->info, list) {
0035         if (entry->conn_handle == info->conn_handle)
0036             return entry;
0037     }
0038     return NULL;
0039 }
0040 
0041 static bool ath_mci_add_profile(struct ath_common *common,
0042                 struct ath_mci_profile *mci,
0043                 struct ath_mci_profile_info *info)
0044 {
0045     struct ath_mci_profile_info *entry;
0046     static const u8 voice_priority[] = { 110, 110, 110, 112, 110, 110, 114, 116, 118 };
0047 
0048     if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) &&
0049         (info->type == MCI_GPM_COEX_PROFILE_VOICE))
0050         return false;
0051 
0052     if (((NUM_PROF(mci) - mci->num_sco) == ATH_MCI_MAX_ACL_PROFILE) &&
0053         (info->type != MCI_GPM_COEX_PROFILE_VOICE))
0054         return false;
0055 
0056     entry = kzalloc(sizeof(*entry), GFP_ATOMIC);
0057     if (!entry)
0058         return false;
0059 
0060     memcpy(entry, info, 10);
0061     INC_PROF(mci, info);
0062     list_add_tail(&entry->list, &mci->info);
0063     if (info->type == MCI_GPM_COEX_PROFILE_VOICE) {
0064         if (info->voice_type < sizeof(voice_priority))
0065             mci->voice_priority = voice_priority[info->voice_type];
0066         else
0067             mci->voice_priority = 110;
0068     }
0069 
0070     return true;
0071 }
0072 
0073 static void ath_mci_del_profile(struct ath_common *common,
0074                 struct ath_mci_profile *mci,
0075                 struct ath_mci_profile_info *entry)
0076 {
0077     if (!entry)
0078         return;
0079 
0080     DEC_PROF(mci, entry);
0081     list_del(&entry->list);
0082     kfree(entry);
0083 }
0084 
0085 void ath_mci_flush_profile(struct ath_mci_profile *mci)
0086 {
0087     struct ath_mci_profile_info *info, *tinfo;
0088 
0089     mci->aggr_limit = 0;
0090     mci->num_mgmt = 0;
0091 
0092     if (list_empty(&mci->info))
0093         return;
0094 
0095     list_for_each_entry_safe(info, tinfo, &mci->info, list) {
0096         list_del(&info->list);
0097         DEC_PROF(mci, info);
0098         kfree(info);
0099     }
0100 }
0101 
0102 static void ath_mci_adjust_aggr_limit(struct ath_btcoex *btcoex)
0103 {
0104     struct ath_mci_profile *mci = &btcoex->mci;
0105     u32 wlan_airtime = btcoex->btcoex_period *
0106                 (100 - btcoex->duty_cycle) / 100;
0107 
0108     /*
0109      * Scale: wlan_airtime is in ms, aggr_limit is in 0.25 ms.
0110      * When wlan_airtime is less than 4ms, aggregation limit has to be
0111      * adjusted half of wlan_airtime to ensure that the aggregation can fit
0112      * without collision with BT traffic.
0113      */
0114     if ((wlan_airtime <= 4) &&
0115         (!mci->aggr_limit || (mci->aggr_limit > (2 * wlan_airtime))))
0116         mci->aggr_limit = 2 * wlan_airtime;
0117 }
0118 
0119 static void ath_mci_update_scheme(struct ath_softc *sc)
0120 {
0121     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0122     struct ath_btcoex *btcoex = &sc->btcoex;
0123     struct ath_mci_profile *mci = &btcoex->mci;
0124     struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
0125     struct ath_mci_profile_info *info;
0126     u32 num_profile = NUM_PROF(mci);
0127 
0128     if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING)
0129         goto skip_tuning;
0130 
0131     mci->aggr_limit = 0;
0132     btcoex->duty_cycle = ath_mci_duty_cycle[num_profile];
0133     btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
0134     if (NUM_PROF(mci))
0135         btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
0136     else
0137         btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL :
0138                             ATH_BTCOEX_STOMP_LOW;
0139 
0140     if (num_profile == 1) {
0141         info = list_first_entry(&mci->info,
0142                     struct ath_mci_profile_info,
0143                     list);
0144         if (mci->num_sco) {
0145             if (info->T == 12)
0146                 mci->aggr_limit = 8;
0147             else if (info->T == 6) {
0148                 mci->aggr_limit = 6;
0149                 btcoex->duty_cycle = 30;
0150             } else
0151                 mci->aggr_limit = 6;
0152             ath_dbg(common, MCI,
0153                 "Single SCO, aggregation limit %d 1/4 ms\n",
0154                 mci->aggr_limit);
0155         } else if (mci->num_pan || mci->num_other_acl) {
0156             /*
0157              * For single PAN/FTP profile, allocate 35% for BT
0158              * to improve WLAN throughput.
0159              */
0160             btcoex->duty_cycle = AR_SREV_9565(sc->sc_ah) ? 40 : 35;
0161             btcoex->btcoex_period = 53;
0162             ath_dbg(common, MCI,
0163                 "Single PAN/FTP bt period %d ms dutycycle %d\n",
0164                 btcoex->duty_cycle, btcoex->btcoex_period);
0165         } else if (mci->num_hid) {
0166             btcoex->duty_cycle = 30;
0167             mci->aggr_limit = 6;
0168             ath_dbg(common, MCI,
0169                 "Multiple attempt/timeout single HID "
0170                 "aggregation limit 1.5 ms dutycycle 30%%\n");
0171         }
0172     } else if (num_profile == 2) {
0173         if (mci->num_hid == 2)
0174             btcoex->duty_cycle = 30;
0175         mci->aggr_limit = 6;
0176         ath_dbg(common, MCI,
0177             "Two BT profiles aggr limit 1.5 ms dutycycle %d%%\n",
0178             btcoex->duty_cycle);
0179     } else if (num_profile >= 3) {
0180         mci->aggr_limit = 4;
0181         ath_dbg(common, MCI,
0182             "Three or more profiles aggregation limit 1 ms\n");
0183     }
0184 
0185 skip_tuning:
0186     if (IS_CHAN_2GHZ(sc->sc_ah->curchan)) {
0187         if (IS_CHAN_HT(sc->sc_ah->curchan))
0188             ath_mci_adjust_aggr_limit(btcoex);
0189         else
0190             btcoex->btcoex_period >>= 1;
0191     }
0192 
0193     ath9k_btcoex_timer_pause(sc);
0194     ath9k_hw_btcoex_disable(sc->sc_ah);
0195 
0196     if (IS_CHAN_5GHZ(sc->sc_ah->curchan))
0197         return;
0198 
0199     btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_BDR_DUTY_CYCLE : 0);
0200     if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)
0201         btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE;
0202 
0203     btcoex->btcoex_no_stomp =  btcoex->btcoex_period *
0204         (100 - btcoex->duty_cycle) / 100;
0205 
0206     ath9k_hw_btcoex_enable(sc->sc_ah);
0207     ath9k_btcoex_timer_resume(sc);
0208 }
0209 
0210 static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
0211 {
0212     struct ath_hw *ah = sc->sc_ah;
0213     struct ath_common *common = ath9k_hw_common(ah);
0214     struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
0215     u32 payload[4] = {0, 0, 0, 0};
0216 
0217     switch (opcode) {
0218     case MCI_GPM_BT_CAL_REQ:
0219         if (mci_hw->bt_state == MCI_BT_AWAKE) {
0220             mci_hw->bt_state = MCI_BT_CAL_START;
0221             ath9k_queue_reset(sc, RESET_TYPE_MCI);
0222         }
0223         ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state);
0224         break;
0225     case MCI_GPM_BT_CAL_GRANT:
0226         MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);
0227         ar9003_mci_send_message(sc->sc_ah, MCI_GPM, 0, payload,
0228                     16, false, true);
0229         break;
0230     default:
0231         ath_dbg(common, MCI, "Unknown GPM CAL message\n");
0232         break;
0233     }
0234 }
0235 
0236 static void ath9k_mci_work(struct work_struct *work)
0237 {
0238     struct ath_softc *sc = container_of(work, struct ath_softc, mci_work);
0239 
0240     ath_mci_update_scheme(sc);
0241 }
0242 
0243 static void ath_mci_update_stomp_txprio(u8 cur_txprio, u8 *stomp_prio)
0244 {
0245     if (cur_txprio < stomp_prio[ATH_BTCOEX_STOMP_NONE])
0246         stomp_prio[ATH_BTCOEX_STOMP_NONE] = cur_txprio;
0247 
0248     if (cur_txprio > stomp_prio[ATH_BTCOEX_STOMP_ALL])
0249         stomp_prio[ATH_BTCOEX_STOMP_ALL] = cur_txprio;
0250 
0251     if ((cur_txprio > ATH_MCI_HI_PRIO) &&
0252         (cur_txprio < stomp_prio[ATH_BTCOEX_STOMP_LOW]))
0253         stomp_prio[ATH_BTCOEX_STOMP_LOW] = cur_txprio;
0254 }
0255 
0256 static void ath_mci_set_concur_txprio(struct ath_softc *sc)
0257 {
0258     struct ath_btcoex *btcoex = &sc->btcoex;
0259     struct ath_mci_profile *mci = &btcoex->mci;
0260     u8 stomp_txprio[ATH_BTCOEX_STOMP_MAX];
0261 
0262     memset(stomp_txprio, 0, sizeof(stomp_txprio));
0263     if (mci->num_mgmt) {
0264         stomp_txprio[ATH_BTCOEX_STOMP_ALL] = ATH_MCI_INQUIRY_PRIO;
0265         if (!mci->num_pan && !mci->num_other_acl)
0266             stomp_txprio[ATH_BTCOEX_STOMP_NONE] =
0267                 ATH_MCI_INQUIRY_PRIO;
0268     } else {
0269         u8 prof_prio[] = { 50, 90, 94, 52 };/* RFCOMM, A2DP, HID, PAN */
0270 
0271         stomp_txprio[ATH_BTCOEX_STOMP_LOW] =
0272         stomp_txprio[ATH_BTCOEX_STOMP_NONE] = 0xff;
0273 
0274         if (mci->num_sco)
0275             ath_mci_update_stomp_txprio(mci->voice_priority,
0276                             stomp_txprio);
0277         if (mci->num_other_acl)
0278             ath_mci_update_stomp_txprio(prof_prio[0], stomp_txprio);
0279         if (mci->num_a2dp)
0280             ath_mci_update_stomp_txprio(prof_prio[1], stomp_txprio);
0281         if (mci->num_hid)
0282             ath_mci_update_stomp_txprio(prof_prio[2], stomp_txprio);
0283         if (mci->num_pan)
0284             ath_mci_update_stomp_txprio(prof_prio[3], stomp_txprio);
0285 
0286         if (stomp_txprio[ATH_BTCOEX_STOMP_NONE] == 0xff)
0287             stomp_txprio[ATH_BTCOEX_STOMP_NONE] = 0;
0288 
0289         if (stomp_txprio[ATH_BTCOEX_STOMP_LOW] == 0xff)
0290             stomp_txprio[ATH_BTCOEX_STOMP_LOW] = 0;
0291     }
0292     ath9k_hw_btcoex_set_concur_txprio(sc->sc_ah, stomp_txprio);
0293 }
0294 
0295 static u8 ath_mci_process_profile(struct ath_softc *sc,
0296                   struct ath_mci_profile_info *info)
0297 {
0298     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0299     struct ath_btcoex *btcoex = &sc->btcoex;
0300     struct ath_mci_profile *mci = &btcoex->mci;
0301     struct ath_mci_profile_info *entry = NULL;
0302 
0303     entry = ath_mci_find_profile(mci, info);
0304     if (entry) {
0305         /*
0306          * Two MCI interrupts are generated while connecting to
0307          * headset and A2DP profile, but only one MCI interrupt
0308          * is generated with last added profile type while disconnecting
0309          * both profiles.
0310          * So while adding second profile type decrement
0311          * the first one.
0312          */
0313         if (entry->type != info->type) {
0314             DEC_PROF(mci, entry);
0315             INC_PROF(mci, info);
0316         }
0317         memcpy(entry, info, 10);
0318     }
0319 
0320     if (info->start) {
0321         if (!entry && !ath_mci_add_profile(common, mci, info))
0322             return 0;
0323     } else
0324         ath_mci_del_profile(common, mci, entry);
0325 
0326     ath_mci_set_concur_txprio(sc);
0327     return 1;
0328 }
0329 
0330 static u8 ath_mci_process_status(struct ath_softc *sc,
0331                  struct ath_mci_profile_status *status)
0332 {
0333     struct ath_btcoex *btcoex = &sc->btcoex;
0334     struct ath_mci_profile *mci = &btcoex->mci;
0335     struct ath_mci_profile_info info;
0336     int i = 0, old_num_mgmt = mci->num_mgmt;
0337 
0338     /* Link status type are not handled */
0339     if (status->is_link)
0340         return 0;
0341 
0342     info.conn_handle = status->conn_handle;
0343     if (ath_mci_find_profile(mci, &info))
0344         return 0;
0345 
0346     if (status->conn_handle >= ATH_MCI_MAX_PROFILE)
0347         return 0;
0348 
0349     if (status->is_critical)
0350         __set_bit(status->conn_handle, mci->status);
0351     else
0352         __clear_bit(status->conn_handle, mci->status);
0353 
0354     mci->num_mgmt = 0;
0355     do {
0356         if (test_bit(i, mci->status))
0357             mci->num_mgmt++;
0358     } while (++i < ATH_MCI_MAX_PROFILE);
0359 
0360     ath_mci_set_concur_txprio(sc);
0361     if (old_num_mgmt != mci->num_mgmt)
0362         return 1;
0363 
0364     return 0;
0365 }
0366 
0367 static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
0368 {
0369     struct ath_hw *ah = sc->sc_ah;
0370     struct ath_mci_profile_info profile_info;
0371     struct ath_mci_profile_status profile_status;
0372     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0373     u8 major, minor, update_scheme = 0;
0374     u32 seq_num;
0375 
0376     if (ar9003_mci_state(ah, MCI_STATE_NEED_FLUSH_BT_INFO) &&
0377         ar9003_mci_state(ah, MCI_STATE_ENABLE)) {
0378         ath_dbg(common, MCI, "(MCI) Need to flush BT profiles\n");
0379         ath_mci_flush_profile(&sc->btcoex.mci);
0380         ar9003_mci_state(ah, MCI_STATE_SEND_STATUS_QUERY);
0381     }
0382 
0383     switch (opcode) {
0384     case MCI_GPM_COEX_VERSION_QUERY:
0385         ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION);
0386         break;
0387     case MCI_GPM_COEX_VERSION_RESPONSE:
0388         major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION);
0389         minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION);
0390         ar9003_mci_set_bt_version(ah, major, minor);
0391         break;
0392     case MCI_GPM_COEX_STATUS_QUERY:
0393         ar9003_mci_send_wlan_channels(ah);
0394         break;
0395     case MCI_GPM_COEX_BT_PROFILE_INFO:
0396         memcpy(&profile_info,
0397                (rx_payload + MCI_GPM_COEX_B_PROFILE_TYPE), 10);
0398 
0399         if ((profile_info.type == MCI_GPM_COEX_PROFILE_UNKNOWN) ||
0400             (profile_info.type >= MCI_GPM_COEX_PROFILE_MAX)) {
0401             ath_dbg(common, MCI,
0402                 "Illegal profile type = %d, state = %d\n",
0403                 profile_info.type,
0404                 profile_info.start);
0405             break;
0406         }
0407 
0408         update_scheme += ath_mci_process_profile(sc, &profile_info);
0409         break;
0410     case MCI_GPM_COEX_BT_STATUS_UPDATE:
0411         profile_status.is_link = *(rx_payload +
0412                        MCI_GPM_COEX_B_STATUS_TYPE);
0413         profile_status.conn_handle = *(rx_payload +
0414                            MCI_GPM_COEX_B_STATUS_LINKID);
0415         profile_status.is_critical = *(rx_payload +
0416                            MCI_GPM_COEX_B_STATUS_STATE);
0417 
0418         seq_num = *((u32 *)(rx_payload + 12));
0419         ath_dbg(common, MCI,
0420             "BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%u\n",
0421             profile_status.is_link, profile_status.conn_handle,
0422             profile_status.is_critical, seq_num);
0423 
0424         update_scheme += ath_mci_process_status(sc, &profile_status);
0425         break;
0426     default:
0427         ath_dbg(common, MCI, "Unknown GPM COEX message = 0x%02x\n", opcode);
0428         break;
0429     }
0430     if (update_scheme)
0431         ieee80211_queue_work(sc->hw, &sc->mci_work);
0432 }
0433 
0434 int ath_mci_setup(struct ath_softc *sc)
0435 {
0436     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0437     struct ath_mci_coex *mci = &sc->mci_coex;
0438     struct ath_mci_buf *buf = &mci->sched_buf;
0439     int ret;
0440 
0441     buf->bf_addr = dmam_alloc_coherent(sc->dev,
0442                   ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE,
0443                   &buf->bf_paddr, GFP_KERNEL);
0444 
0445     if (buf->bf_addr == NULL) {
0446         ath_dbg(common, FATAL, "MCI buffer alloc failed\n");
0447         return -ENOMEM;
0448     }
0449 
0450     memset(buf->bf_addr, MCI_GPM_RSVD_PATTERN,
0451            ATH_MCI_SCHED_BUF_SIZE + ATH_MCI_GPM_BUF_SIZE);
0452 
0453     mci->sched_buf.bf_len = ATH_MCI_SCHED_BUF_SIZE;
0454 
0455     mci->gpm_buf.bf_len = ATH_MCI_GPM_BUF_SIZE;
0456     mci->gpm_buf.bf_addr = mci->sched_buf.bf_addr + mci->sched_buf.bf_len;
0457     mci->gpm_buf.bf_paddr = mci->sched_buf.bf_paddr + mci->sched_buf.bf_len;
0458 
0459     ret = ar9003_mci_setup(sc->sc_ah, mci->gpm_buf.bf_paddr,
0460                    mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4),
0461                    mci->sched_buf.bf_paddr);
0462     if (ret) {
0463         ath_err(common, "Failed to initialize MCI\n");
0464         return ret;
0465     }
0466 
0467     INIT_WORK(&sc->mci_work, ath9k_mci_work);
0468     ath_dbg(common, MCI, "MCI Initialized\n");
0469 
0470     return 0;
0471 }
0472 
0473 void ath_mci_cleanup(struct ath_softc *sc)
0474 {
0475     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0476     struct ath_hw *ah = sc->sc_ah;
0477 
0478     ar9003_mci_cleanup(ah);
0479 
0480     ath_dbg(common, MCI, "MCI De-Initialized\n");
0481 }
0482 
0483 void ath_mci_intr(struct ath_softc *sc)
0484 {
0485     struct ath_mci_coex *mci = &sc->mci_coex;
0486     struct ath_hw *ah = sc->sc_ah;
0487     struct ath_common *common = ath9k_hw_common(ah);
0488     struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci;
0489     u32 mci_int, mci_int_rxmsg;
0490     u32 offset, subtype, opcode;
0491     u32 *pgpm;
0492     u32 more_data = MCI_GPM_MORE;
0493     bool skip_gpm = false;
0494 
0495     ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg);
0496 
0497     if (ar9003_mci_state(ah, MCI_STATE_ENABLE) == 0) {
0498         ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET);
0499         return;
0500     }
0501 
0502     if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) {
0503         u32 payload[4] = { 0xffffffff, 0xffffffff,
0504                    0xffffffff, 0xffffff00};
0505 
0506         /*
0507          * The following REMOTE_RESET and SYS_WAKING used to sent
0508          * only when BT wake up. Now they are always sent, as a
0509          * recovery method to reset BT MCI's RX alignment.
0510          */
0511         ar9003_mci_send_message(ah, MCI_REMOTE_RESET, 0,
0512                     payload, 16, true, false);
0513         ar9003_mci_send_message(ah, MCI_SYS_WAKING, 0,
0514                     NULL, 0, true, false);
0515 
0516         mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE;
0517         ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE);
0518 
0519         /*
0520          * always do this for recovery and 2G/5G toggling and LNA_TRANS
0521          */
0522         ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE);
0523     }
0524 
0525     if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) {
0526         mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING;
0527 
0528         if ((mci_hw->bt_state == MCI_BT_SLEEP) &&
0529             (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP) !=
0530              MCI_BT_SLEEP))
0531             ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE);
0532     }
0533 
0534     if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) {
0535         mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING;
0536 
0537         if ((mci_hw->bt_state == MCI_BT_AWAKE) &&
0538             (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP) !=
0539              MCI_BT_AWAKE))
0540             mci_hw->bt_state = MCI_BT_SLEEP;
0541     }
0542 
0543     if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
0544         (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
0545         ar9003_mci_state(ah, MCI_STATE_RECOVER_RX);
0546         skip_gpm = true;
0547     }
0548 
0549     if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) {
0550         mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO;
0551         ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET);
0552     }
0553 
0554     if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) {
0555         mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM;
0556 
0557         while (more_data == MCI_GPM_MORE) {
0558             if (test_bit(ATH_OP_HW_RESET, &common->op_flags))
0559                 return;
0560 
0561             pgpm = mci->gpm_buf.bf_addr;
0562             offset = ar9003_mci_get_next_gpm_offset(ah, &more_data);
0563 
0564             if (offset == MCI_GPM_INVALID)
0565                 break;
0566 
0567             pgpm += (offset >> 2);
0568 
0569             /*
0570              * The first dword is timer.
0571              * The real data starts from 2nd dword.
0572              */
0573             subtype = MCI_GPM_TYPE(pgpm);
0574             opcode = MCI_GPM_OPCODE(pgpm);
0575 
0576             if (skip_gpm)
0577                 goto recycle;
0578 
0579             if (MCI_GPM_IS_CAL_TYPE(subtype)) {
0580                 ath_mci_cal_msg(sc, subtype, (u8 *)pgpm);
0581             } else {
0582                 switch (subtype) {
0583                 case MCI_GPM_COEX_AGENT:
0584                     ath_mci_msg(sc, opcode, (u8 *)pgpm);
0585                     break;
0586                 default:
0587                     break;
0588                 }
0589             }
0590         recycle:
0591             MCI_GPM_RECYCLE(pgpm);
0592         }
0593     }
0594 
0595     if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_HW_MSG_MASK) {
0596         if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL)
0597             mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL;
0598 
0599         if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_LNA_INFO)
0600             mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO;
0601 
0602         if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) {
0603             int value_dbm = MS(mci_hw->cont_status,
0604                        AR_MCI_CONT_RSSI_POWER);
0605 
0606             mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO;
0607 
0608             ath_dbg(common, MCI,
0609                 "MCI CONT_INFO: (%s) pri = %d pwr = %d dBm\n",
0610                 MS(mci_hw->cont_status, AR_MCI_CONT_TXRX) ?
0611                 "tx" : "rx",
0612                 MS(mci_hw->cont_status, AR_MCI_CONT_PRIORITY),
0613                 value_dbm);
0614         }
0615 
0616         if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK)
0617             mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_NACK;
0618 
0619         if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_RST)
0620             mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_RST;
0621     }
0622 
0623     if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) ||
0624         (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
0625         mci_int &= ~(AR_MCI_INTERRUPT_RX_INVALID_HDR |
0626                  AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT);
0627         ath_mci_msg(sc, MCI_GPM_COEX_NOOP, NULL);
0628     }
0629 }
0630 
0631 void ath_mci_enable(struct ath_softc *sc)
0632 {
0633     struct ath_common *common = ath9k_hw_common(sc->sc_ah);
0634 
0635     if (!common->btcoex_enabled)
0636         return;
0637 
0638     if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
0639         sc->sc_ah->imask |= ATH9K_INT_MCI;
0640 }
0641 
0642 void ath9k_mci_update_wlan_channels(struct ath_softc *sc, bool allow_all)
0643 {
0644     struct ath_hw *ah = sc->sc_ah;
0645     struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci;
0646     struct ath9k_channel *chan = ah->curchan;
0647     u32 channelmap[] = {0x00000000, 0xffff0000, 0xffffffff, 0x7fffffff};
0648     int i;
0649     s16 chan_start, chan_end;
0650     u16 wlan_chan;
0651 
0652     if (!chan || !IS_CHAN_2GHZ(chan))
0653         return;
0654 
0655     if (allow_all)
0656         goto send_wlan_chan;
0657 
0658     wlan_chan = chan->channel - 2402;
0659 
0660     chan_start = wlan_chan - 10;
0661     chan_end = wlan_chan + 10;
0662 
0663     if (IS_CHAN_HT40PLUS(chan))
0664         chan_end += 20;
0665     else if (IS_CHAN_HT40MINUS(chan))
0666         chan_start -= 20;
0667 
0668     /* adjust side band */
0669     chan_start -= 7;
0670     chan_end += 7;
0671 
0672     if (chan_start <= 0)
0673         chan_start = 0;
0674     if (chan_end >= ATH_MCI_NUM_BT_CHANNELS)
0675         chan_end = ATH_MCI_NUM_BT_CHANNELS - 1;
0676 
0677     ath_dbg(ath9k_hw_common(ah), MCI,
0678         "WLAN current channel %d mask BT channel %d - %d\n",
0679         wlan_chan, chan_start, chan_end);
0680 
0681     for (i = chan_start; i < chan_end; i++)
0682         MCI_GPM_CLR_CHANNEL_BIT(&channelmap, i);
0683 
0684 send_wlan_chan:
0685     /* update and send wlan channels info to BT */
0686     for (i = 0; i < 4; i++)
0687         mci->wlan_channels[i] = channelmap[i];
0688     ar9003_mci_send_wlan_channels(ah);
0689     ar9003_mci_state(ah, MCI_STATE_SEND_VERSION_QUERY);
0690 }
0691 
0692 void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,
0693                bool concur_tx)
0694 {
0695     struct ath_hw *ah = sc->sc_ah;
0696     struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
0697     bool old_concur_tx = mci_hw->concur_tx;
0698 
0699     if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX)) {
0700         mci_hw->concur_tx = false;
0701         return;
0702     }
0703 
0704     if (!IS_CHAN_2GHZ(ah->curchan))
0705         return;
0706 
0707     if (setchannel) {
0708         struct ath9k_hw_cal_data *caldata = &sc->cur_chan->caldata;
0709         if (IS_CHAN_HT40PLUS(ah->curchan) &&
0710             (ah->curchan->channel > caldata->channel) &&
0711             (ah->curchan->channel <= caldata->channel + 20))
0712             return;
0713         if (IS_CHAN_HT40MINUS(ah->curchan) &&
0714             (ah->curchan->channel < caldata->channel) &&
0715             (ah->curchan->channel >= caldata->channel - 20))
0716             return;
0717         mci_hw->concur_tx = false;
0718     } else
0719         mci_hw->concur_tx = concur_tx;
0720 
0721     if (old_concur_tx != mci_hw->concur_tx)
0722         ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false);
0723 }
0724 
0725 static void ath9k_mci_stomp_audio(struct ath_softc *sc)
0726 {
0727     struct ath_hw *ah = sc->sc_ah;
0728     struct ath_btcoex *btcoex = &sc->btcoex;
0729     struct ath_mci_profile *mci = &btcoex->mci;
0730 
0731     if (!mci->num_sco && !mci->num_a2dp)
0732         return;
0733 
0734     if (ah->stats.avgbrssi > 25) {
0735         btcoex->stomp_audio = 0;
0736         return;
0737     }
0738 
0739     btcoex->stomp_audio++;
0740 }
0741 void ath9k_mci_update_rssi(struct ath_softc *sc)
0742 {
0743     struct ath_hw *ah = sc->sc_ah;
0744     struct ath_btcoex *btcoex = &sc->btcoex;
0745     struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
0746 
0747     ath9k_mci_stomp_audio(sc);
0748 
0749     if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX))
0750         return;
0751 
0752     if (ah->stats.avgbrssi >= 40) {
0753         if (btcoex->rssi_count < 0)
0754             btcoex->rssi_count = 0;
0755         if (++btcoex->rssi_count >= ATH_MCI_CONCUR_TX_SWITCH) {
0756             btcoex->rssi_count = 0;
0757             ath9k_mci_set_txpower(sc, false, true);
0758         }
0759     } else {
0760         if (btcoex->rssi_count > 0)
0761             btcoex->rssi_count = 0;
0762         if (--btcoex->rssi_count <= -ATH_MCI_CONCUR_TX_SWITCH) {
0763             btcoex->rssi_count = 0;
0764             ath9k_mci_set_txpower(sc, false, false);
0765         }
0766     }
0767 }