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