Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/dev/ath/if_ath_btcoex.c
39534 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2013 Adrian Chadd <[email protected]>
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer,
12
* without modification.
13
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
14
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
15
* redistribution must be conditioned upon including a substantially
16
* similar Disclaimer requirement for further binary redistribution.
17
*
18
* NO WARRANTY
19
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
22
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
24
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
27
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
29
* THE POSSIBILITY OF SUCH DAMAGES.
30
*/
31
#include <sys/cdefs.h>
32
/*
33
* This implements some very basic bluetooth coexistence methods for
34
* the ath(4) hardware.
35
*/
36
#include "opt_ath.h"
37
#include "opt_inet.h"
38
#include "opt_wlan.h"
39
40
#include <sys/param.h>
41
#include <sys/systm.h>
42
#include <sys/sysctl.h>
43
#include <sys/kernel.h>
44
#include <sys/lock.h>
45
#include <sys/malloc.h>
46
#include <sys/mutex.h>
47
#include <sys/errno.h>
48
#include <machine/bus.h>
49
#include <machine/resource.h>
50
51
#include <sys/bus.h>
52
53
#include <sys/socket.h>
54
55
#include <net/if.h>
56
#include <net/if_var.h>
57
#include <net/if_media.h>
58
#include <net/if_arp.h>
59
#include <net/ethernet.h> /* XXX for ether_sprintf */
60
61
#include <net80211/ieee80211_var.h>
62
63
#include <net/bpf.h>
64
65
#ifdef INET
66
#include <netinet/in.h>
67
#include <netinet/if_ether.h>
68
#endif
69
70
#include <dev/ath/if_athvar.h>
71
#include <dev/ath/if_ath_btcoex.h>
72
#include <dev/ath/if_ath_btcoex_mci.h>
73
74
MALLOC_DECLARE(M_ATHDEV);
75
76
/*
77
* Initial AR9285 / (WB195) bluetooth coexistence settings,
78
* just for experimentation.
79
*
80
* Return 0 for OK; errno for error.
81
*
82
* XXX TODO: There needs to be a PCIe workaround to disable ASPM if
83
* bluetooth coexistence is enabled.
84
*/
85
static int
86
ath_btcoex_cfg_wb195(struct ath_softc *sc)
87
{
88
HAL_BT_COEX_INFO btinfo;
89
HAL_BT_COEX_CONFIG btconfig;
90
struct ath_hal *ah = sc->sc_ah;
91
92
if (! ath_hal_btcoex_supported(ah))
93
return (EINVAL);
94
95
bzero(&btinfo, sizeof(btinfo));
96
bzero(&btconfig, sizeof(btconfig));
97
98
device_printf(sc->sc_dev, "Enabling WB195 BTCOEX\n");
99
100
btinfo.bt_module = HAL_BT_MODULE_JANUS;
101
btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE;
102
/*
103
* These are the three GPIO pins hooked up between the AR9285 and
104
* the AR3011.
105
*/
106
btinfo.bt_gpio_bt_active = 6;
107
btinfo.bt_gpio_bt_priority = 7;
108
btinfo.bt_gpio_wlan_active = 5;
109
btinfo.bt_active_polarity = 1; /* XXX not used */
110
btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */
111
btinfo.bt_isolation = 0; /* in dB, not used */
112
113
ath_hal_btcoex_set_info(ah, &btinfo);
114
115
btconfig.bt_time_extend = 0;
116
btconfig.bt_txstate_extend = 1; /* true */
117
btconfig.bt_txframe_extend = 1; /* true */
118
btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED;
119
btconfig.bt_quiet_collision = 1; /* true */
120
btconfig.bt_rxclear_polarity = 1; /* true */
121
btconfig.bt_priority_time = 2;
122
btconfig.bt_first_slot_time = 5;
123
btconfig.bt_hold_rxclear = 1; /* true */
124
125
ath_hal_btcoex_set_config(ah, &btconfig);
126
127
/*
128
* Enable antenna diversity.
129
*/
130
ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1);
131
132
return (0);
133
}
134
135
/*
136
* Initial AR9485 / (WB225) bluetooth coexistence settings,
137
* just for experimentation.
138
*
139
* Return 0 for OK; errno for error.
140
*/
141
static int
142
ath_btcoex_cfg_wb225(struct ath_softc *sc)
143
{
144
HAL_BT_COEX_INFO btinfo;
145
HAL_BT_COEX_CONFIG btconfig;
146
struct ath_hal *ah = sc->sc_ah;
147
148
if (! ath_hal_btcoex_supported(ah))
149
return (EINVAL);
150
151
bzero(&btinfo, sizeof(btinfo));
152
bzero(&btconfig, sizeof(btconfig));
153
154
device_printf(sc->sc_dev, "Enabling WB225 BTCOEX\n");
155
156
btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */
157
btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE;
158
/*
159
* These are the three GPIO pins hooked up between the AR9485 and
160
* the bluetooth module.
161
*/
162
btinfo.bt_gpio_bt_active = 4;
163
btinfo.bt_gpio_bt_priority = 8;
164
btinfo.bt_gpio_wlan_active = 5;
165
166
btinfo.bt_active_polarity = 1; /* XXX not used */
167
btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */
168
btinfo.bt_isolation = 0; /* in dB, not used */
169
170
ath_hal_btcoex_set_info(ah, &btinfo);
171
172
btconfig.bt_time_extend = 0;
173
btconfig.bt_txstate_extend = 1; /* true */
174
btconfig.bt_txframe_extend = 1; /* true */
175
btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED;
176
btconfig.bt_quiet_collision = 1; /* true */
177
btconfig.bt_rxclear_polarity = 1; /* true */
178
btconfig.bt_priority_time = 2;
179
btconfig.bt_first_slot_time = 5;
180
btconfig.bt_hold_rxclear = 1; /* true */
181
182
ath_hal_btcoex_set_config(ah, &btconfig);
183
184
/*
185
* Enable antenna diversity.
186
*/
187
ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1);
188
189
return (0);
190
}
191
192
static int
193
ath_btcoex_cfg_mci(struct ath_softc *sc, uint32_t mci_cfg, int do_btdiv)
194
{
195
HAL_BT_COEX_INFO btinfo;
196
HAL_BT_COEX_CONFIG btconfig;
197
struct ath_hal *ah = sc->sc_ah;
198
199
if (! ath_hal_btcoex_supported(ah))
200
return (EINVAL);
201
202
bzero(&btinfo, sizeof(btinfo));
203
bzero(&btconfig, sizeof(btconfig));
204
205
sc->sc_ah->ah_config.ath_hal_mci_config = mci_cfg;
206
207
if (ath_btcoex_mci_attach(sc) != 0) {
208
device_printf(sc->sc_dev, "Failed to setup btcoex\n");
209
return (EINVAL);
210
}
211
212
btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */
213
btinfo.bt_coex_config = HAL_BT_COEX_CFG_MCI;
214
215
/*
216
* MCI uses a completely different interface to speak
217
* to the bluetooth module - it's a command based
218
* thing over a serial line, rather than
219
* state pins to/from the bluetooth module.
220
*
221
* So, the GPIO configuration, polarity, etc
222
* doesn't matter on MCI devices; it's just
223
* completely ignored by the HAL.
224
*/
225
btinfo.bt_gpio_bt_active = 4;
226
btinfo.bt_gpio_bt_priority = 8;
227
btinfo.bt_gpio_wlan_active = 5;
228
229
btinfo.bt_active_polarity = 1; /* XXX not used */
230
btinfo.bt_single_ant = 0; /* 2 antenna on WB335 */
231
btinfo.bt_isolation = 0; /* in dB, not used */
232
233
ath_hal_btcoex_set_info(ah, &btinfo);
234
235
btconfig.bt_time_extend = 0;
236
btconfig.bt_txstate_extend = 1; /* true */
237
btconfig.bt_txframe_extend = 1; /* true */
238
btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED;
239
btconfig.bt_quiet_collision = 1; /* true */
240
btconfig.bt_rxclear_polarity = 1; /* true */
241
btconfig.bt_priority_time = 2;
242
btconfig.bt_first_slot_time = 5;
243
btconfig.bt_hold_rxclear = 1; /* true */
244
245
ath_hal_btcoex_set_config(ah, &btconfig);
246
247
/* Enable */
248
ath_hal_btcoex_enable(sc->sc_ah);
249
250
/* Stomp */
251
ath_hal_btcoex_set_weights(ah, HAL_BT_COEX_STOMP_NONE);
252
253
/*
254
* Enable antenna diversity.
255
*/
256
ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY,
257
do_btdiv);
258
259
return (0);
260
}
261
262
/*
263
* Initial AR9462 / (WB222) bluetooth coexistence settings.
264
*
265
* Return 0 for OK; errno for error.
266
*/
267
static int
268
ath_btcoex_cfg_wb222(struct ath_softc *sc)
269
{
270
271
device_printf(sc->sc_dev, "Enabling WB222 BTCOEX\n");
272
/* XXX from ath9k */
273
return (ath_btcoex_cfg_mci(sc, 0x2201, 1));
274
}
275
276
/*
277
* Initial QCA9565 / (WB335B) bluetooth coexistence settings.
278
*
279
* Return 0 for OK; errno for error.
280
*/
281
static int
282
ath_btcoex_cfg_wb335b(struct ath_softc *sc)
283
{
284
uint32_t flags;
285
int do_btdiv = 0;
286
287
/* ath9k default */
288
flags = 0xa4c1;
289
290
/* 1-ant and 2-ant AR9565 */
291
/*
292
* XXX TODO: ensure these actually make it down to the
293
* HAL correctly!
294
*/
295
if (sc->sc_pci_devinfo & ATH_PCI_AR9565_1ANT) {
296
flags &= ~ATH_MCI_CONFIG_ANT_ARCH;
297
flags |= ATH_MCI_ANT_ARCH_1_ANT_PA_LNA_SHARED <<
298
ATH_MCI_CONFIG_ANT_ARCH_S;
299
} else if (sc->sc_pci_devinfo & ATH_PCI_AR9565_2ANT) {
300
flags &= ~ATH_MCI_CONFIG_ANT_ARCH;
301
flags |= ATH_MCI_ANT_ARCH_2_ANT_PA_LNA_NON_SHARED <<
302
ATH_MCI_CONFIG_ANT_ARCH_S;
303
}
304
305
if (sc->sc_pci_devinfo & ATH_PCI_BT_ANT_DIV) {
306
do_btdiv = 1;
307
}
308
309
device_printf(sc->sc_dev, "Enabling WB335 BTCOEX\n");
310
/* XXX from ath9k */
311
return (ath_btcoex_cfg_mci(sc, flags, do_btdiv));
312
}
313
314
#if 0
315
/*
316
* When using bluetooth coexistence, ASPM needs to be disabled
317
* otherwise the sleeping interferes with the bluetooth (USB)
318
* operation and the MAC sleep/wakeup hardware.
319
*
320
* The PCIe powersave routine also needs to not be called
321
* by the driver during suspend/resume, else things will get
322
* a little odd. Check Linux ath9k for more details.
323
*/
324
static int
325
ath_btcoex_aspm_wb195(struct ath_softc *sc)
326
{
327
328
/* XXX TODO: clear device ASPM L0S and L1 */
329
/* XXX TODO: clear _parent_ ASPM L0S and L1 */
330
}
331
#endif
332
333
/*
334
* Methods which are required
335
*/
336
337
/*
338
* Attach btcoex to the given interface
339
*/
340
int
341
ath_btcoex_attach(struct ath_softc *sc)
342
{
343
int ret;
344
struct ath_hal *ah = sc->sc_ah;
345
const char *profname;
346
347
/*
348
* No chipset bluetooth coexistence? Then do nothing.
349
*/
350
if (! ath_hal_btcoex_supported(ah))
351
return (0);
352
353
/*
354
* Look at the hints to determine which bluetooth
355
* profile to configure.
356
*/
357
ret = resource_string_value(device_get_name(sc->sc_dev),
358
device_get_unit(sc->sc_dev),
359
"btcoex_profile",
360
&profname);
361
if (ret != 0) {
362
/* nothing to do */
363
return (0);
364
}
365
366
if (strncmp(profname, "wb195", 5) == 0) {
367
ret = ath_btcoex_cfg_wb195(sc);
368
} else if (strncmp(profname, "wb222", 5) == 0) {
369
ret = ath_btcoex_cfg_wb222(sc);
370
} else if (strncmp(profname, "wb225", 5) == 0) {
371
ret = ath_btcoex_cfg_wb225(sc);
372
} else if (strncmp(profname, "wb335", 5) == 0) {
373
ret = ath_btcoex_cfg_wb335b(sc);
374
} else {
375
return (0);
376
}
377
378
/*
379
* Propagate up failure from the actual attach phase.
380
*/
381
if (ret != 0)
382
return (ret);
383
384
return (0);
385
}
386
387
/*
388
* Detach btcoex from the given interface
389
*/
390
int
391
ath_btcoex_detach(struct ath_softc *sc)
392
{
393
if (sc->sc_btcoex_mci) {
394
ath_btcoex_mci_detach(sc);
395
}
396
397
return (0);
398
}
399
400
/*
401
* Configure or disable bluetooth coexistence on the given channel.
402
*
403
* For AR9285/AR9287/AR9485, we'll never see a 5GHz channel, so we just
404
* assume bluetooth coexistence is always on.
405
*
406
* For AR9462, we may see a 5GHz channel; bluetooth coexistence should
407
* not be enabled on those channels.
408
*/
409
int
410
ath_btcoex_enable(struct ath_softc *sc, const struct ieee80211_channel *chan)
411
{
412
if (sc->sc_btcoex_mci) {
413
ath_btcoex_mci_enable(sc, chan);
414
}
415
416
return (0);
417
}
418
419
/*
420
* Handle ioctl requests from the diagnostic interface.
421
*
422
* The initial part of this code resembles ath_ioctl_diag();
423
* it's likely a good idea to reduce duplication between
424
* these two routines.
425
*/
426
int
427
ath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad)
428
{
429
unsigned int id = ad->ad_id & ATH_DIAG_ID;
430
void *indata = NULL;
431
void *outdata = NULL;
432
u_int32_t insize = ad->ad_in_size;
433
u_int32_t outsize = ad->ad_out_size;
434
int error = 0;
435
// int val;
436
437
if (ad->ad_id & ATH_DIAG_IN) {
438
/*
439
* Copy in data.
440
*/
441
indata = malloc(insize, M_TEMP, M_NOWAIT);
442
if (indata == NULL) {
443
error = ENOMEM;
444
goto bad;
445
}
446
error = copyin(ad->ad_in_data, indata, insize);
447
if (error)
448
goto bad;
449
}
450
if (ad->ad_id & ATH_DIAG_DYN) {
451
/*
452
* Allocate a buffer for the results (otherwise the HAL
453
* returns a pointer to a buffer where we can read the
454
* results). Note that we depend on the HAL leaving this
455
* pointer for us to use below in reclaiming the buffer;
456
* may want to be more defensive.
457
*/
458
outdata = malloc(outsize, M_TEMP, M_NOWAIT | M_ZERO);
459
if (outdata == NULL) {
460
error = ENOMEM;
461
goto bad;
462
}
463
}
464
switch (id) {
465
default:
466
error = EINVAL;
467
goto bad;
468
}
469
if (outsize < ad->ad_out_size)
470
ad->ad_out_size = outsize;
471
if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
472
error = EFAULT;
473
bad:
474
if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
475
free(indata, M_TEMP);
476
if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
477
free(outdata, M_TEMP);
478
return (error);
479
}
480
481