xref: /dragonfly/sys/dev/netif/ath/ath/if_ath_btcoex.c (revision 0de090e1)
1 /*-
2  * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  *
29  * $FreeBSD$
30  */
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 /*
35  * This implements some very basic bluetooth coexistence methods for
36  * the ath(4) hardware.
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 #if defined(__DragonFly__)
52 /* empty */
53 #else
54 #include <machine/bus.h>
55 #include <machine/resource.h>
56 #endif
57 #include <sys/bus.h>
58 
59 #include <sys/socket.h>
60 
61 #include <net/if.h>
62 #include <net/if_var.h>
63 #include <net/if_media.h>
64 #include <net/if_arp.h>
65 #include <net/ethernet.h>		/* XXX for ether_sprintf */
66 
67 #include <netproto/802_11/ieee80211_var.h>
68 
69 #include <net/bpf.h>
70 
71 #ifdef INET
72 #include <netinet/in.h>
73 #include <netinet/if_ether.h>
74 #endif
75 
76 #include <dev/netif/ath/ath/if_athvar.h>
77 #include <dev/netif/ath/ath/if_ath_btcoex.h>
78 
79 /*
80  * Initial AR9285 / (WB195) bluetooth coexistence settings,
81  * just for experimentation.
82  *
83  * Return 0 for OK; errno for error.
84  *
85  * XXX TODO: There needs to be a PCIe workaround to disable ASPM if
86  * bluetooth coexistence is enabled.
87  */
88 static int
89 ath_btcoex_cfg_wb195(struct ath_softc *sc)
90 {
91 	HAL_BT_COEX_INFO btinfo;
92 	HAL_BT_COEX_CONFIG btconfig;
93 	struct ath_hal *ah = sc->sc_ah;
94 
95 	if (! ath_hal_btcoex_supported(ah))
96 		return (EINVAL);
97 
98 	bzero(&btinfo, sizeof(btinfo));
99 	bzero(&btconfig, sizeof(btconfig));
100 
101 	device_printf(sc->sc_dev, "Enabling WB195 BTCOEX\n");
102 
103 	btinfo.bt_module = HAL_BT_MODULE_JANUS;
104 	btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE;
105 	/*
106 	 * These are the three GPIO pins hooked up between the AR9285 and
107 	 * the AR3011.
108 	 */
109 	btinfo.bt_gpio_bt_active = 6;
110 	btinfo.bt_gpio_bt_priority = 7;
111 	btinfo.bt_gpio_wlan_active = 5;
112 	btinfo.bt_active_polarity = 1;	/* XXX not used */
113 	btinfo.bt_single_ant = 1;	/* 1 antenna on ar9285 ? */
114 	btinfo.bt_isolation = 0;	/* in dB, not used */
115 
116 	ath_hal_btcoex_set_info(ah, &btinfo);
117 
118 	btconfig.bt_time_extend = 0;
119 	btconfig.bt_txstate_extend = 1;	/* true */
120 	btconfig.bt_txframe_extend = 1;	/* true */
121 	btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED;
122 	btconfig.bt_quiet_collision = 1;	/* true */
123 	btconfig.bt_rxclear_polarity = 1;	/* true */
124 	btconfig.bt_priority_time = 2;
125 	btconfig.bt_first_slot_time = 5;
126 	btconfig.bt_hold_rxclear = 1;	/* true */
127 
128 	ath_hal_btcoex_set_config(ah, &btconfig);
129 
130 	/*
131 	 * Enable antenna diversity.
132 	 */
133 	ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1);
134 
135 	return (0);
136 }
137 
138 /*
139  * Initial AR9485 / (WB225) bluetooth coexistence settings,
140  * just for experimentation.
141  *
142  * Return 0 for OK; errno for error.
143  */
144 static int
145 ath_btcoex_cfg_wb225(struct ath_softc *sc)
146 {
147 	HAL_BT_COEX_INFO btinfo;
148 	HAL_BT_COEX_CONFIG btconfig;
149 	struct ath_hal *ah = sc->sc_ah;
150 
151 	if (! ath_hal_btcoex_supported(ah))
152 		return (EINVAL);
153 
154 	bzero(&btinfo, sizeof(btinfo));
155 	bzero(&btconfig, sizeof(btconfig));
156 
157 	device_printf(sc->sc_dev, "Enabling WB225 BTCOEX\n");
158 
159 	btinfo.bt_module = HAL_BT_MODULE_JANUS;	/* XXX not used? */
160 	btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE;
161 	/*
162 	 * These are the three GPIO pins hooked up between the AR9485 and
163 	 * the bluetooth module.
164 	 */
165 	btinfo.bt_gpio_bt_active = 4;
166 	btinfo.bt_gpio_bt_priority = 8;
167 	btinfo.bt_gpio_wlan_active = 5;
168 
169 	btinfo.bt_active_polarity = 1;	/* XXX not used */
170 	btinfo.bt_single_ant = 1;	/* 1 antenna on ar9285 ? */
171 	btinfo.bt_isolation = 0;	/* in dB, not used */
172 
173 	ath_hal_btcoex_set_info(ah, &btinfo);
174 
175 	btconfig.bt_time_extend = 0;
176 	btconfig.bt_txstate_extend = 1;	/* true */
177 	btconfig.bt_txframe_extend = 1;	/* true */
178 	btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED;
179 	btconfig.bt_quiet_collision = 1;	/* true */
180 	btconfig.bt_rxclear_polarity = 1;	/* true */
181 	btconfig.bt_priority_time = 2;
182 	btconfig.bt_first_slot_time = 5;
183 	btconfig.bt_hold_rxclear = 1;	/* true */
184 
185 	ath_hal_btcoex_set_config(ah, &btconfig);
186 
187 	/*
188 	 * Enable antenna diversity.
189 	 */
190 	ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1);
191 
192 	return (0);
193 }
194 
195 /*
196  * Initial AR9462 / (WB222) bluetooth coexistence settings,
197  * just for experimentation.
198  *
199  * Return 0 for OK; errno for error.
200  */
201 static int
202 ath_btcoex_cfg_wb222(struct ath_softc *sc)
203 {
204 	HAL_BT_COEX_INFO btinfo;
205 	HAL_BT_COEX_CONFIG btconfig;
206 	struct ath_hal *ah = sc->sc_ah;
207 
208 	if (! ath_hal_btcoex_supported(ah))
209 		return (EINVAL);
210 
211 	bzero(&btinfo, sizeof(btinfo));
212 	bzero(&btconfig, sizeof(btconfig));
213 
214 	device_printf(sc->sc_dev, "Enabling WB222 BTCOEX\n");
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 WB222 */
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 	/*
252 	 * Enable antenna diversity.
253 	 */
254 	ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1);
255 
256 	return (0);
257 }
258 
259 
260 
261 
262 #if 0
263 /*
264  * When using bluetooth coexistence, ASPM needs to be disabled
265  * otherwise the sleeping interferes with the bluetooth (USB)
266  * operation and the MAC sleep/wakeup hardware.
267  *
268  * The PCIe powersave routine also needs to not be called
269  * by the driver during suspend/resume, else things will get
270  * a little odd.  Check Linux ath9k for more details.
271  */
272 static int
273 ath_btcoex_aspm_wb195(struct ath_softc *sc)
274 {
275 
276 	/* XXX TODO: clear device ASPM L0S and L1 */
277 	/* XXX TODO: clear _parent_ ASPM L0S and L1 */
278 }
279 #endif
280 
281 /*
282  * Methods which are required
283  */
284 
285 /*
286  * Attach btcoex to the given interface
287  */
288 int
289 ath_btcoex_attach(struct ath_softc *sc)
290 {
291 	int ret;
292 	struct ath_hal *ah = sc->sc_ah;
293 	const char *profname;
294 
295 	/*
296 	 * No chipset bluetooth coexistence? Then do nothing.
297 	 */
298 	if (! ath_hal_btcoex_supported(ah))
299 		return (0);
300 
301 	/*
302 	 * Look at the hints to determine which bluetooth
303 	 * profile to configure.
304 	 */
305 	ret = resource_string_value(device_get_name(sc->sc_dev),
306 	    device_get_unit(sc->sc_dev),
307 	    "btcoex_profile",
308 	    &profname);
309 	if (ret != 0) {
310 		/* nothing to do */
311 		return (0);
312 	}
313 
314 	if (strncmp(profname, "wb195", 5) == 0) {
315 		ret = ath_btcoex_cfg_wb195(sc);
316 	} else if (strncmp(profname, "wb222", 5) == 0) {
317 		ret = ath_btcoex_cfg_wb222(sc);
318 	} else if (strncmp(profname, "wb225", 5) == 0) {
319 		ret = ath_btcoex_cfg_wb225(sc);
320 	} else {
321 		return (0);
322 	}
323 
324 	/*
325 	 * Propagate up failure from the actual attach phase.
326 	 */
327 	if (ret != 0)
328 		return (ret);
329 
330 	return (0);
331 }
332 
333 /*
334  * Detach btcoex from the given interface
335  */
336 int
337 ath_btcoex_detach(struct ath_softc *sc)
338 {
339 
340 	return (0);
341 }
342 
343 /*
344  * Configure or disable bluetooth coexistence on the given channel.
345  *
346  * For AR9285/AR9287/AR9485, we'll never see a 5GHz channel, so we just
347  * assume bluetooth coexistence is always on.
348  *
349  * For AR9462, we may see a 5GHz channel; bluetooth coexistence should
350  * not be enabled on those channels.
351  */
352 int
353 ath_btcoex_enable(struct ath_softc *sc, const struct ieee80211_channel *chan)
354 {
355 
356 	return (0);
357 }
358 
359 /*
360  * Handle ioctl requests from the diagnostic interface.
361  *
362  * The initial part of this code resembles ath_ioctl_diag();
363  * it's likely a good idea to reduce duplication between
364  * these two routines.
365  */
366 int
367 ath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad)
368 {
369 	unsigned int id = ad->ad_id & ATH_DIAG_ID;
370 	void *indata = NULL;
371 	void *outdata = NULL;
372 	u_int32_t insize = ad->ad_in_size;
373 	u_int32_t outsize = ad->ad_out_size;
374 	int error = 0;
375 //	int val;
376 
377 	if (ad->ad_id & ATH_DIAG_IN) {
378 		/*
379 		 * Copy in data.
380 		 */
381 		indata = kmalloc(insize, M_TEMP, M_INTWAIT);
382 		if (indata == NULL) {
383 			error = ENOMEM;
384 			goto bad;
385 		}
386 		error = copyin(ad->ad_in_data, indata, insize);
387 		if (error)
388 			goto bad;
389 	}
390 	if (ad->ad_id & ATH_DIAG_DYN) {
391 		/*
392 		 * Allocate a buffer for the results (otherwise the HAL
393 		 * returns a pointer to a buffer where we can read the
394 		 * results).  Note that we depend on the HAL leaving this
395 		 * pointer for us to use below in reclaiming the buffer;
396 		 * may want to be more defensive.
397 		 */
398 		outdata = kmalloc(outsize, M_TEMP, M_INTWAIT);
399 		if (outdata == NULL) {
400 			error = ENOMEM;
401 			goto bad;
402 		}
403 	}
404 	switch (id) {
405 		default:
406 			error = EINVAL;
407 	}
408 	if (outsize < ad->ad_out_size)
409 		ad->ad_out_size = outsize;
410 	if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
411 		error = EFAULT;
412 bad:
413 	if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
414 		kfree(indata, M_TEMP);
415 	if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
416 		kfree(outdata, M_TEMP);
417 	return (error);
418 }
419 
420