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