]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ath/if_ath_btcoex_mci.c
Upgrade to OpenSSH 7.7p1.
[FreeBSD/FreeBSD.git] / sys / dev / ath / if_ath_btcoex_mci.c
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$
31  */
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
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 }