The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ath/if_ath_btcoex_mci.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2014 Qualcomm Atheros, Inc.
    3  * Copyright (c) 2016 Adrian Chadd <adrian@FreeBSD.org>
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer,
   11  *    without modification.
   12  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   13  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
   14  *    redistribution must be conditioned upon including a substantially
   15  *    similar Disclaimer requirement for further binary redistribution.
   16  *
   17  * NO WARRANTY
   18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   20  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
   21  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   22  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
   23  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
   26  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
   28  * THE POSSIBILITY OF SUCH DAMAGES.
   29  *
   30  * $FreeBSD: releng/11.2/sys/dev/ath/if_ath_btcoex_mci.c 301182 2016-06-02 01:59:41Z gnn $
   31  */
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD: releng/11.2/sys/dev/ath/if_ath_btcoex_mci.c 301182 2016-06-02 01:59:41Z gnn $");
   34 
   35 /*
   36  * This implements the MCI bluetooth coexistence handling.
   37  */
   38 #include "opt_ath.h"
   39 #include "opt_inet.h"
   40 #include "opt_wlan.h"
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/sysctl.h>
   45 #include <sys/kernel.h>
   46 #include <sys/lock.h>
   47 #include <sys/malloc.h>
   48 #include <sys/mutex.h>
   49 #include <sys/errno.h>
   50 
   51 #include <machine/bus.h>
   52 #include <machine/resource.h>
   53 
   54 #include <sys/bus.h>
   55 
   56 #include <sys/socket.h>
   57 
   58 #include <net/if.h>
   59 #include <net/if_var.h>
   60 #include <net/if_media.h>
   61 #include <net/if_arp.h>
   62 #include <net/ethernet.h>               /* XXX for ether_sprintf */
   63 
   64 #include <net80211/ieee80211_var.h>
   65 
   66 #include <net/bpf.h>
   67 
   68 #ifdef INET
   69 #include <netinet/in.h>
   70 #include <netinet/if_ether.h>
   71 #endif
   72 
   73 #include <dev/ath/if_athvar.h>
   74 #include <dev/ath/if_ath_debug.h>
   75 #include <dev/ath/if_ath_descdma.h>
   76 #include <dev/ath/if_ath_btcoex.h>
   77 
   78 #include <dev/ath/if_ath_btcoex_mci.h>
   79 
   80 MALLOC_DECLARE(M_ATHDEV);
   81 
   82 #define ATH_MCI_GPM_MAX_ENTRY           16
   83 #define ATH_MCI_GPM_BUF_SIZE            (ATH_MCI_GPM_MAX_ENTRY * 16)
   84 #define ATH_MCI_SCHED_BUF_SIZE          (16 * 16) /* 16 entries, 4 dword each */
   85 
   86 static void ath_btcoex_mci_update_wlan_channels(struct ath_softc *sc);
   87 
   88 int
   89 ath_btcoex_mci_attach(struct ath_softc *sc)
   90 {
   91         int buflen, error;
   92 
   93         buflen = ATH_MCI_GPM_BUF_SIZE + ATH_MCI_SCHED_BUF_SIZE;
   94         error = ath_descdma_alloc_desc(sc, &sc->sc_btcoex.buf, NULL,
   95             "MCI bufs", buflen, 1);
   96         if (error != 0) {
   97                 device_printf(sc->sc_dev, "%s: failed to alloc MCI RAM\n",
   98                     __func__);
   99                 return (error);
  100         }
  101 
  102         /* Yes, we're going to do bluetooth MCI coex */
  103         sc->sc_btcoex_mci = 1;
  104 
  105         /* Initialise the wlan channel mapping */
  106         sc->sc_btcoex.wlan_channels[0] = 0x00000000;
  107         sc->sc_btcoex.wlan_channels[1] = 0xffffffff;
  108         sc->sc_btcoex.wlan_channels[2] = 0xffffffff;
  109         sc->sc_btcoex.wlan_channels[3] = 0x7fffffff;
  110 
  111         /*
  112          * Ok, so the API is a bit odd. It assumes sched_addr is
  113          * after gpm_addr, and it does math to figure out the right
  114          * sched_buf pointer.
  115          *
  116          * So, set gpm_addr to buf, sched_addr to gpm_addr + ATH_MCI_GPM_BUF_SIZE,
  117          * the HAL call with do (gpm_buf + (sched_addr - gpm_addr)) to
  118          * set sched_buf, and we're "golden".
  119          *
  120          * Note, it passes in 'len' here (gpm_len) as
  121          * ATH_MCI_GPM_BUF_SIZE >> 4.  My guess is that it's 16
  122          * bytes per entry and we're storing 16 entries.
  123          */
  124         sc->sc_btcoex.gpm_buf = (void *) sc->sc_btcoex.buf.dd_desc;
  125         sc->sc_btcoex.sched_buf = sc->sc_btcoex.gpm_buf +
  126             ATH_MCI_GPM_BUF_SIZE;
  127 
  128         sc->sc_btcoex.gpm_paddr = sc->sc_btcoex.buf.dd_desc_paddr;
  129         sc->sc_btcoex.sched_paddr = sc->sc_btcoex.gpm_paddr +
  130             ATH_MCI_GPM_BUF_SIZE;
  131 
  132         /* memset the gpm buffer with MCI_GPM_RSVD_PATTERN */
  133         memset(sc->sc_btcoex.gpm_buf, 0xfe, buflen);
  134 
  135         /*
  136          * This is an unfortunate x86'ism in the HAL - the
  137          * HAL code expects the passed in buffer to be
  138          * coherent, and doesn't implement /any/ kind
  139          * of buffer sync operations at all.
  140          *
  141          * So, this code will only work on dma coherent buffers
  142          * and will behave poorly on non-coherent systems.
  143          * Fixing this would require some HAL surgery so it
  144          * actually /did/ the buffer flushing as appropriate.
  145          */
  146         ath_hal_btcoex_mci_setup(sc->sc_ah,
  147             sc->sc_btcoex.gpm_paddr,
  148             sc->sc_btcoex.gpm_buf,
  149             ATH_MCI_GPM_BUF_SIZE >> 4,
  150             sc->sc_btcoex.sched_paddr);
  151 
  152         return (0);
  153 }
  154 
  155 /*
  156  * Detach btcoex from the given interface
  157  */
  158 int
  159 ath_btcoex_mci_detach(struct ath_softc *sc)
  160 {
  161 
  162         ath_hal_btcoex_mci_detach(sc->sc_ah);
  163         ath_descdma_cleanup(sc, &sc->sc_btcoex.buf, NULL);
  164         return (0);
  165 }
  166 
  167 /*
  168  * Configure or disable bluetooth coexistence on the given channel.
  169  *
  170  * For MCI, we just use the top-level enable/disable flag, and
  171  * then the MCI reset / channel update path will configure things
  172  * appropriately based on the current band.
  173  */
  174 int
  175 ath_btcoex_mci_enable(struct ath_softc *sc,
  176     const struct ieee80211_channel *chan)
  177 {
  178 
  179         /*
  180          * Always reconfigure stomp-all for now, so wlan wins.
  181          *
  182          * The default weights still don't allow beacons to win,
  183          * so unless you set net.wlan.X.bmiss_max to something higher,
  184          * net80211 will disconnect you during a HCI INQUIRY command.
  185          *
  186          * The longer-term solution is to dynamically adjust whether
  187          * bmiss happens based on bluetooth requirements, and look at
  188          * making the individual stomp bits configurable.
  189          */
  190         ath_hal_btcoex_set_weights(sc->sc_ah, HAL_BT_COEX_STOMP_ALL);
  191 
  192         /*
  193          * update wlan channels so the firmware knows what channels it
  194          * can/can't use.
  195          */
  196         ath_btcoex_mci_update_wlan_channels(sc);
  197 
  198         return (0);
  199 }
  200 
  201 /*
  202  * XXX TODO: turn into general btcoex, and then make this
  203  * the MCI specific bits.
  204  */
  205 static void
  206 ath_btcoex_mci_event(struct ath_softc *sc, ATH_BT_COEX_EVENT nevent,
  207     void *param)
  208 {
  209 
  210         if (! sc->sc_btcoex_mci)
  211                 return;
  212 
  213         /*
  214          * Check whether we need to flush our local profile cache.
  215          * If we do, then at (XXX TODO) we should flush our state,
  216          * then wait for the MCI response with the updated profile list.
  217          */
  218         if (ath_hal_btcoex_mci_state(sc->sc_ah,
  219             HAL_MCI_STATE_NEED_FLUSH_BT_INFO, NULL) != 0) {
  220                 uint32_t data = 0;
  221 
  222                 if (ath_hal_btcoex_mci_state(sc->sc_ah,
  223                     HAL_MCI_STATE_ENABLE, NULL) != 0) {
  224                         DPRINTF(sc, ATH_DEBUG_BTCOEX,
  225                             "(MCI) Flush BT profile\n");
  226                         /*
  227                          * XXX TODO: flush profile state on the ath(4)
  228                          * driver side; subsequent messages will come
  229                          * through with the current list of active
  230                          * profiles.
  231                          */
  232                         ath_hal_btcoex_mci_state(sc->sc_ah,
  233                             HAL_MCI_STATE_NEED_FLUSH_BT_INFO, &data);
  234                         ath_hal_btcoex_mci_state(sc->sc_ah,
  235                             HAL_MCI_STATE_SEND_STATUS_QUERY, NULL);
  236                 }
  237         }
  238         if (nevent == ATH_COEX_EVENT_BT_NOOP) {
  239                 DPRINTF(sc, ATH_DEBUG_BTCOEX, "(MCI) BT_NOOP\n");
  240                 return;
  241         }
  242 }
  243 
  244 static void
  245 ath_btcoex_mci_send_gpm(struct ath_softc *sc, uint32_t *payload)
  246 {
  247 
  248         ath_hal_btcoex_mci_send_message(sc->sc_ah, MCI_GPM, 0, payload, 16,
  249             AH_FALSE, AH_TRUE);
  250 }
  251 
  252 /*
  253  * This starts a BT calibration.  It requires a chip reset.
  254  */
  255 static int
  256 ath_btcoex_mci_bt_cal_do(struct ath_softc *sc, int tx_timeout, int rx_timeout)
  257 {
  258 
  259         device_printf(sc->sc_dev, "%s: TODO!\n", __func__);
  260         return (0);
  261 }
  262 
  263 static void
  264 ath_btcoex_mci_cal_msg(struct ath_softc *sc, uint8_t opcode,
  265     uint8_t *rx_payload)
  266 {
  267         uint32_t payload[4] = {0, 0, 0, 0};
  268 
  269         switch (opcode) {
  270         case MCI_GPM_BT_CAL_REQ:
  271                 DPRINTF(sc, ATH_DEBUG_BTCOEX, "(MCI) receive BT_CAL_REQ\n");
  272                 if (ath_hal_btcoex_mci_state(sc->sc_ah, HAL_MCI_STATE_BT,
  273                     NULL) == MCI_BT_AWAKE) {
  274                         ath_hal_btcoex_mci_state(sc->sc_ah,
  275                             HAL_MCI_STATE_SET_BT_CAL_START, NULL);
  276                         ath_btcoex_mci_bt_cal_do(sc, 1000, 1000);
  277                 } else {
  278                         DPRINTF(sc, ATH_DEBUG_BTCOEX,
  279                             "(MCI) State mismatches: %d\n",
  280                             ath_hal_btcoex_mci_state(sc->sc_ah,
  281                             HAL_MCI_STATE_BT, NULL));
  282                 }
  283                 break;
  284         case MCI_GPM_BT_CAL_DONE:
  285                 DPRINTF(sc, ATH_DEBUG_BTCOEX, "(MCI) receive BT_CAL_DONE\n");
  286                 if (ath_hal_btcoex_mci_state(sc->sc_ah, HAL_MCI_STATE_BT,
  287                     NULL) == MCI_BT_CAL) {
  288                         DPRINTF(sc, ATH_DEBUG_BTCOEX,
  289                             "(MCI) ERROR ILLEGAL!\n");
  290                 } else {
  291                         DPRINTF(sc, ATH_DEBUG_BTCOEX,
  292                             "(MCI) BT not in CAL state.\n");
  293                 }
  294                 break;
  295         case MCI_GPM_BT_CAL_GRANT:
  296                 DPRINTF(sc, ATH_DEBUG_BTCOEX, "(MCI) receive BT_CAL_GRANT\n");
  297                 /* Send WLAN_CAL_DONE for now */
  298                 DPRINTF(sc, ATH_DEBUG_BTCOEX, "(MCI) Send WLAN_CAL_DONE\n");
  299                 MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE);
  300                 ath_btcoex_mci_send_gpm(sc, &payload[0]);
  301                 break;
  302         default:
  303                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  304                     "(MCI) Unknown GPM CAL message.\n");
  305                 break;
  306         }
  307 }
  308 
  309 /*
  310  * Update the bluetooth channel map.
  311  *
  312  * This map tells the bluetooth device which bluetooth channels
  313  * are available for data.
  314  *
  315  * For 5GHz, all channels are available.
  316  * For 2GHz, the current wifi channel range is blocked out,
  317  *   and the rest are available.
  318  *
  319  * This narrows which frequencies are used by the device when
  320  * it initiates a transfer, thus hopefully reducing the chances
  321  * of collisions (both hopefully on the current device and
  322  * other devices in the same channel.)
  323  */
  324 static void
  325 ath_btcoex_mci_update_wlan_channels(struct ath_softc *sc)
  326 {
  327         struct ieee80211com *ic = &sc->sc_ic;
  328         struct ieee80211_channel *chan = ic->ic_curchan;
  329         uint32_t channel_info[4] =
  330             { 0x00000000, 0xffffffff, 0xffffffff, 0x7fffffff };
  331         int32_t wl_chan, bt_chan, bt_start = 0, bt_end = 79;
  332 
  333         /* BT channel frequency is 2402 + k, k = 0 ~ 78 */
  334         if (IEEE80211_IS_CHAN_2GHZ(chan)) {
  335                 wl_chan = chan->ic_freq - 2402;
  336                 if (IEEE80211_IS_CHAN_HT40U(chan)) {
  337                         bt_start = wl_chan - 10;
  338                         bt_end = wl_chan + 30;
  339                 } else if (IEEE80211_IS_CHAN_HT40D(chan)) {
  340                         bt_start = wl_chan - 30;
  341                         bt_end = wl_chan + 10;
  342                 } else {
  343                         /* Assume 20MHz */
  344                         bt_start = wl_chan - 10;
  345                         bt_end = wl_chan + 10;
  346                 }
  347 
  348                 bt_start -= 7;
  349                 bt_end += 7;
  350 
  351                 if (bt_start < 0) {
  352                         bt_start = 0;
  353                 }
  354                 if (bt_end > MCI_NUM_BT_CHANNELS) {
  355                         bt_end = MCI_NUM_BT_CHANNELS;
  356                 }
  357                 DPRINTF(sc, ATH_DEBUG_BTCOEX, "(MCI) WLAN use channel %d\n",
  358                     chan->ic_freq);
  359                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  360                     "(MCI) mask BT channel %d - %d\n", bt_start, bt_end);
  361                 for (bt_chan = bt_start; bt_chan < bt_end; bt_chan++) {
  362                         MCI_GPM_CLR_CHANNEL_BIT(&channel_info[0], bt_chan);
  363                 }
  364         } else {
  365                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  366                     "(MCI) WLAN not use any 2G channel, unmask all for BT\n");
  367         }
  368         ath_hal_btcoex_mci_state(sc->sc_ah, HAL_MCI_STATE_SEND_WLAN_CHANNELS,
  369             &channel_info[0]);
  370 }
  371 
  372 static void
  373 ath_btcoex_mci_coex_msg(struct ath_softc *sc, uint8_t opcode,
  374     uint8_t *rx_payload)
  375 {
  376         uint32_t version;
  377         uint8_t major;
  378         uint8_t minor;
  379         uint32_t seq_num;
  380 
  381         switch (opcode) {
  382         case MCI_GPM_COEX_VERSION_QUERY:
  383                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  384                     "(MCI) Recv GPM COEX Version Query.\n");
  385                 version = ath_hal_btcoex_mci_state(sc->sc_ah,
  386                     HAL_MCI_STATE_SEND_WLAN_COEX_VERSION, NULL);
  387                 break;
  388 
  389         case MCI_GPM_COEX_VERSION_RESPONSE:
  390                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  391                     "(MCI) Recv GPM COEX Version Response.\n");
  392                 major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION);
  393                 minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION);
  394                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  395                     "(MCI) BT Coex version: %d.%d\n", major, minor);
  396                 version = (major << 8) + minor;
  397                 version = ath_hal_btcoex_mci_state(sc->sc_ah,
  398                     HAL_MCI_STATE_SET_BT_COEX_VERSION, &version);
  399                 break;
  400 
  401         case MCI_GPM_COEX_STATUS_QUERY:
  402                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  403                     "(MCI) Recv GPM COEX Status Query = 0x%02x.\n",
  404                     *(rx_payload + MCI_GPM_COEX_B_WLAN_BITMAP));
  405                 ath_hal_btcoex_mci_state(sc->sc_ah,
  406                     HAL_MCI_STATE_SEND_WLAN_CHANNELS, NULL);
  407                 break;
  408 
  409         case MCI_GPM_COEX_BT_PROFILE_INFO:
  410                 /*
  411                  * XXX TODO: here is where we'd parse active profile
  412                  * info and make driver/stack choices as appropriate.
  413                  */
  414                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  415                     "(MCI) TODO: Recv GPM COEX BT_Profile_Info.\n");
  416                 break;
  417 
  418         case MCI_GPM_COEX_BT_STATUS_UPDATE:
  419                 seq_num = *((uint32_t *)(rx_payload + 12));
  420                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  421                     "(MCI) Recv GPM COEX BT_Status_Update: SEQ=%d\n",
  422                     seq_num);
  423                 break;
  424 
  425         default:
  426                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  427                     "(MCI) Unknown GPM COEX message = 0x%02x\n", opcode);
  428                 break;
  429         }
  430 }
  431 
  432 void
  433 ath_btcoex_mci_intr(struct ath_softc *sc)
  434 {
  435         uint32_t mciInt, mciIntRxMsg;
  436         uint32_t offset, subtype, opcode;
  437         uint32_t *pGpm;
  438         uint32_t more_data = HAL_MCI_GPM_MORE;
  439         int8_t value_dbm;
  440         bool skip_gpm = false;
  441 
  442         DPRINTF(sc, ATH_DEBUG_BTCOEX, "%s: called\n", __func__);
  443 
  444         ath_hal_btcoex_mci_get_interrupt(sc->sc_ah, &mciInt, &mciIntRxMsg);
  445 
  446         if (ath_hal_btcoex_mci_state(sc->sc_ah, HAL_MCI_STATE_ENABLE,
  447             NULL) == 0) {
  448                 ath_hal_btcoex_mci_state(sc->sc_ah,
  449                     HAL_MCI_STATE_INIT_GPM_OFFSET, NULL);
  450                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  451                     "(MCI) INTR but MCI_disabled\n");
  452                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  453                     "(MCI) MCI interrupt: mciInt = 0x%x, mciIntRxMsg = 0x%x\n",
  454                     mciInt, mciIntRxMsg);
  455                 return;
  456         }
  457 
  458         if (mciIntRxMsg & HAL_MCI_INTERRUPT_RX_MSG_REQ_WAKE) {
  459                 uint32_t payload4[4] = { 0xffffffff, 0xffffffff, 0xffffffff,
  460                     0xffffff00};
  461 
  462                 /*
  463                  * The following REMOTE_RESET and SYS_WAKING used to sent
  464                  * only when BT wake up. Now they are always sent, as a
  465                  * recovery method to reset BT MCI's RX alignment.
  466                  */
  467                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  468                     "(MCI) 1. INTR Send REMOTE_RESET\n");
  469                 ath_hal_btcoex_mci_send_message(sc->sc_ah,
  470                     MCI_REMOTE_RESET, 0, payload4, 16, AH_TRUE, AH_FALSE);
  471                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  472                     "(MCI) 1. INTR Send SYS_WAKING\n");
  473                 ath_hal_btcoex_mci_send_message(sc->sc_ah,
  474                     MCI_SYS_WAKING, 0, NULL, 0, AH_TRUE, AH_FALSE);
  475 
  476                 mciIntRxMsg &= ~HAL_MCI_INTERRUPT_RX_MSG_REQ_WAKE;
  477                 ath_hal_btcoex_mci_state(sc->sc_ah,
  478                     HAL_MCI_STATE_RESET_REQ_WAKE, NULL);
  479 
  480                 /* always do this for recovery and 2G/5G toggling and LNA_TRANS */
  481                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  482                     "(MCI) 1. Set BT state to AWAKE.\n");
  483                 ath_hal_btcoex_mci_state(sc->sc_ah,
  484                     HAL_MCI_STATE_SET_BT_AWAKE, NULL);
  485         }
  486 
  487         /* Processing SYS_WAKING/SYS_SLEEPING */
  488         if (mciIntRxMsg & HAL_MCI_INTERRUPT_RX_MSG_SYS_WAKING) {
  489                 mciIntRxMsg &= ~HAL_MCI_INTERRUPT_RX_MSG_SYS_WAKING;
  490                 if (ath_hal_btcoex_mci_state(sc->sc_ah, HAL_MCI_STATE_BT,
  491                     NULL) == MCI_BT_SLEEP) {
  492                         if (ath_hal_btcoex_mci_state(sc->sc_ah,
  493                             HAL_MCI_STATE_REMOTE_SLEEP, NULL) == MCI_BT_SLEEP) {
  494                                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  495                                     "(MCI) 2. BT stays in SLEEP mode.\n");
  496                         } else {
  497                                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  498                                     "(MCI) 2. Set BT state to AWAKE.\n");
  499                                 ath_hal_btcoex_mci_state(sc->sc_ah,
  500                                     HAL_MCI_STATE_SET_BT_AWAKE, NULL);
  501                         }
  502                 } else {
  503                         DPRINTF(sc, ATH_DEBUG_BTCOEX,
  504                             "(MCI) 2. BT stays in AWAKE mode.\n");
  505                 }
  506         }
  507 
  508         if (mciIntRxMsg & HAL_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) {
  509                 mciIntRxMsg &= ~HAL_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING;
  510                 if (ath_hal_btcoex_mci_state(sc->sc_ah, HAL_MCI_STATE_BT,
  511                     NULL) == MCI_BT_AWAKE) {
  512                         if (ath_hal_btcoex_mci_state(sc->sc_ah,
  513                             HAL_MCI_STATE_REMOTE_SLEEP, NULL) == MCI_BT_AWAKE) {
  514                                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  515                                     "(MCI) 3. BT stays in AWAKE mode.\n");
  516                         } else {
  517                                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  518                                     "(MCI) 3. Set BT state to SLEEP.\n");
  519                                 ath_hal_btcoex_mci_state(sc->sc_ah,
  520                                     HAL_MCI_STATE_SET_BT_SLEEP, NULL);
  521                         }
  522                 } else {
  523                         DPRINTF(sc, ATH_DEBUG_BTCOEX,
  524                             "(MCI) 3. BT stays in SLEEP mode.\n");
  525                 }
  526         }
  527 
  528         /*
  529          * Recover from out-of-order / wrong-offset GPM messages.
  530          */
  531         if ((mciInt & HAL_MCI_INTERRUPT_RX_INVALID_HDR) ||
  532             (mciInt & HAL_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
  533                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  534                     "(MCI) MCI RX broken, skip GPM messages\n");
  535                 ath_hal_btcoex_mci_state(sc->sc_ah,
  536                     HAL_MCI_STATE_RECOVER_RX, NULL);
  537                 skip_gpm = true;
  538         }
  539 
  540         if (mciIntRxMsg & HAL_MCI_INTERRUPT_RX_MSG_SCHD_INFO) {
  541                 mciIntRxMsg &= ~HAL_MCI_INTERRUPT_RX_MSG_SCHD_INFO;
  542                 offset = ath_hal_btcoex_mci_state(sc->sc_ah,
  543                     HAL_MCI_STATE_LAST_SCHD_MSG_OFFSET, NULL);
  544         }
  545 
  546         /*
  547          * Parse GPM messages.
  548          */
  549         if (mciIntRxMsg & HAL_MCI_INTERRUPT_RX_MSG_GPM) {
  550                 mciIntRxMsg &= ~HAL_MCI_INTERRUPT_RX_MSG_GPM;
  551 
  552                 while (more_data == HAL_MCI_GPM_MORE) {
  553                         pGpm = (void *) sc->sc_btcoex.gpm_buf;
  554                         offset = ath_hal_btcoex_mci_state(sc->sc_ah,
  555                             HAL_MCI_STATE_NEXT_GPM_OFFSET, &more_data);
  556 
  557                         if (offset == HAL_MCI_GPM_INVALID)
  558                                 break;
  559                         pGpm += (offset >> 2);
  560                         /*
  561                          * The first DWORD is a timer.
  562                          * The real data starts from the second DWORD.
  563                          */
  564                         subtype = MCI_GPM_TYPE(pGpm);
  565                         opcode = MCI_GPM_OPCODE(pGpm);
  566 
  567                         if (!skip_gpm) {
  568                                 if (MCI_GPM_IS_CAL_TYPE(subtype)) {
  569                                         ath_btcoex_mci_cal_msg(sc, subtype,
  570                                             (uint8_t*) pGpm);
  571                                 } else {
  572                                         switch (subtype) {
  573                                         case MCI_GPM_COEX_AGENT:
  574                                                 ath_btcoex_mci_coex_msg(sc,
  575                                                     opcode, (uint8_t*) pGpm);
  576                                         break;
  577                                         case MCI_GPM_BT_DEBUG:
  578                                                 device_printf(sc->sc_dev,
  579                                                     "(MCI) TODO: GPM_BT_DEBUG!\n");
  580                                         break;
  581                                         default:
  582                                                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  583                                                     "(MCI) Unknown GPM message.\n");
  584                                                 break;
  585                                         }
  586                                 }
  587                         }
  588                         MCI_GPM_RECYCLE(pGpm);
  589                 }
  590         }
  591 
  592         /*
  593          * This is monitoring/management information messages, so the driver
  594          * layer can hook in and dynamically adjust things like aggregation
  595          * size, expected bluetooth/wifi traffic throughput, etc.
  596          *
  597          * None of that is done right now; it just passes off the values
  598          * to the HAL so it can update its internal state as appropriate.
  599          * This code just prints out the values for debugging purposes.
  600          */
  601         if (mciIntRxMsg & HAL_MCI_INTERRUPT_RX_MSG_MONITOR) {
  602                 if (mciIntRxMsg & HAL_MCI_INTERRUPT_RX_MSG_LNA_CONTROL) {
  603                         mciIntRxMsg &= ~HAL_MCI_INTERRUPT_RX_MSG_LNA_CONTROL;
  604                         DPRINTF(sc, ATH_DEBUG_BTCOEX, "(MCI) LNA_CONTROL\n");
  605                 }
  606                 if (mciIntRxMsg & HAL_MCI_INTERRUPT_RX_MSG_LNA_INFO) {
  607                         mciIntRxMsg &= ~HAL_MCI_INTERRUPT_RX_MSG_LNA_INFO;
  608                         DPRINTF(sc, ATH_DEBUG_BTCOEX, "(MCI) LNA_INFO\n");
  609                 }
  610                 if (mciIntRxMsg & HAL_MCI_INTERRUPT_RX_MSG_CONT_INFO) {
  611                         value_dbm = ath_hal_btcoex_mci_state(sc->sc_ah,
  612                             HAL_MCI_STATE_CONT_RSSI_POWER, NULL);
  613 
  614                         mciIntRxMsg &= ~HAL_MCI_INTERRUPT_RX_MSG_CONT_INFO;
  615                         if (ath_hal_btcoex_mci_state(sc->sc_ah,
  616                             HAL_MCI_STATE_CONT_TXRX, NULL)) {
  617                                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  618                                     "(MCI) CONT_INFO: (tx) pri = %d, pwr = %d dBm\n",
  619                                 ath_hal_btcoex_mci_state(sc->sc_ah,
  620                                     HAL_MCI_STATE_CONT_PRIORITY, NULL),
  621                                     value_dbm);
  622                         } else {
  623                                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  624                                     "(MCI) CONT_INFO: (rx) pri = %d, rssi = %d dBm\n",
  625                                 ath_hal_btcoex_mci_state(sc->sc_ah,
  626                                     HAL_MCI_STATE_CONT_PRIORITY, NULL),
  627                                     value_dbm);
  628                         }
  629                 }
  630                 if (mciIntRxMsg & HAL_MCI_INTERRUPT_RX_MSG_CONT_NACK) {
  631                         mciIntRxMsg &= ~HAL_MCI_INTERRUPT_RX_MSG_CONT_NACK;
  632                         DPRINTF(sc, ATH_DEBUG_BTCOEX, "(MCI) CONT_NACK\n");
  633                 }
  634                 if (mciIntRxMsg & HAL_MCI_INTERRUPT_RX_MSG_CONT_RST) {
  635                         mciIntRxMsg &= ~HAL_MCI_INTERRUPT_RX_MSG_CONT_RST;
  636                         DPRINTF(sc, ATH_DEBUG_BTCOEX, "(MCI) CONT_RST\n");
  637                 }
  638         }
  639 
  640         /*
  641          * Recover the state engine if we hit an invalid header/timeout.
  642          * This is the final part of GPT out-of-sync recovery.
  643          */
  644         if ((mciInt & HAL_MCI_INTERRUPT_RX_INVALID_HDR) ||
  645             (mciInt & HAL_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) {
  646                 ath_btcoex_mci_event(sc, ATH_COEX_EVENT_BT_NOOP, NULL);
  647                 mciInt &= ~(HAL_MCI_INTERRUPT_RX_INVALID_HDR |
  648                     HAL_MCI_INTERRUPT_CONT_INFO_TIMEOUT);
  649         }
  650 
  651         if (mciIntRxMsg & 0xfffffffe) {
  652                 DPRINTF(sc, ATH_DEBUG_BTCOEX,
  653                     "(MCI) Not processed IntRxMsg = 0x%x\n", mciIntRxMsg);
  654         }
  655 }

Cache object: de75062d06c923233fc7fa4c5833228d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.