if_ath_btcoex.c revision 332320
1331722Seadler/*-
2239281Sgonzo * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org>
3239281Sgonzo * All rights reserved.
4239281Sgonzo *
5239281Sgonzo * Redistribution and use in source and binary forms, with or without
6239281Sgonzo * modification, are permitted provided that the following conditions
7239281Sgonzo * are met:
8239281Sgonzo * 1. Redistributions of source code must retain the above copyright
9239281Sgonzo *    notice, this list of conditions and the following disclaimer,
10239281Sgonzo *    without modification.
11239281Sgonzo * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12239281Sgonzo *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13239281Sgonzo *    redistribution must be conditioned upon including a substantially
14239281Sgonzo *    similar Disclaimer requirement for further binary redistribution.
15239281Sgonzo *
16239281Sgonzo * NO WARRANTY
17239281Sgonzo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18239281Sgonzo * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19239281Sgonzo * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20239281Sgonzo * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21239281Sgonzo * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22239281Sgonzo * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23239281Sgonzo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24239281Sgonzo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25239281Sgonzo * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26239281Sgonzo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27239281Sgonzo * THE POSSIBILITY OF SUCH DAMAGES.
28239281Sgonzo *
29239281Sgonzo * $FreeBSD: stable/10/sys/dev/ath/if_ath_btcoex.c 332320 2018-04-09 12:53:15Z emaste $
30239281Sgonzo */
31239281Sgonzo#include <sys/cdefs.h>
32239281Sgonzo__FBSDID("$FreeBSD: stable/10/sys/dev/ath/if_ath_btcoex.c 332320 2018-04-09 12:53:15Z emaste $");
33239281Sgonzo
34299069Spfg/*
35239281Sgonzo * This implements some very basic bluetooth coexistence methods for
36239281Sgonzo * the ath(4) hardware.
37239281Sgonzo */
38239281Sgonzo#include "opt_ath.h"
39239281Sgonzo#include "opt_inet.h"
40239281Sgonzo#include "opt_wlan.h"
41239281Sgonzo
42239281Sgonzo#include <sys/param.h>
43239281Sgonzo#include <sys/systm.h>
44239281Sgonzo#include <sys/sysctl.h>
45239281Sgonzo#include <sys/kernel.h>
46239281Sgonzo#include <sys/lock.h>
47239281Sgonzo#include <sys/mutex.h>
48239281Sgonzo#include <sys/errno.h>
49239281Sgonzo
50239281Sgonzo#include <machine/bus.h>
51239281Sgonzo#include <machine/resource.h>
52239281Sgonzo#include <sys/bus.h>
53239281Sgonzo
54239281Sgonzo#include <sys/socket.h>
55239281Sgonzo
56239281Sgonzo#include <net/if.h>
57239281Sgonzo#include <net/if_media.h>
58266648Sandrew#include <net/if_arp.h>
59239281Sgonzo#include <net/ethernet.h>		/* XXX for ether_sprintf */
60239281Sgonzo
61239281Sgonzo#include <net80211/ieee80211_var.h>
62266648Sandrew
63239281Sgonzo#include <net/bpf.h>
64239281Sgonzo
65239281Sgonzo#ifdef INET
66239281Sgonzo#include <netinet/in.h>
67239281Sgonzo#include <netinet/if_ether.h>
68266648Sandrew#endif
69266648Sandrew
70239281Sgonzo#include <dev/ath/if_athvar.h>
71239281Sgonzo#include <dev/ath/if_ath_btcoex.h>
72239281Sgonzo
73239281Sgonzo/*
74239281Sgonzo * Initial AR9285 / (WB195) bluetooth coexistence settings,
75239281Sgonzo * just for experimentation.
76239281Sgonzo *
77239281Sgonzo * Return 0 for OK; errno for error.
78239281Sgonzo *
79239281Sgonzo * XXX TODO: There needs to be a PCIe workaround to disable ASPM if
80239281Sgonzo * bluetooth coexistence is enabled.
81239281Sgonzo */
82239281Sgonzostatic int
83239281Sgonzoath_btcoex_cfg_wb195(struct ath_softc *sc)
84239281Sgonzo{
85239281Sgonzo	HAL_BT_COEX_INFO btinfo;
86239281Sgonzo	HAL_BT_COEX_CONFIG btconfig;
87239281Sgonzo	struct ath_hal *ah = sc->sc_ah;
88239281Sgonzo
89239281Sgonzo	if (! ath_hal_btcoex_supported(ah))
90239281Sgonzo		return (EINVAL);
91239281Sgonzo
92239281Sgonzo	bzero(&btinfo, sizeof(btinfo));
93266648Sandrew	bzero(&btconfig, sizeof(btconfig));
94266648Sandrew
95266648Sandrew	device_printf(sc->sc_dev, "Enabling WB195 BTCOEX\n");
96266648Sandrew
97266648Sandrew	btinfo.bt_module = HAL_BT_MODULE_JANUS;
98266648Sandrew	btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE;
99266648Sandrew	/*
100266648Sandrew	 * These are the three GPIO pins hooked up between the AR9285 and
101266648Sandrew	 * the AR3011.
102266648Sandrew	 */
103266648Sandrew	btinfo.bt_gpio_bt_active = 6;
104266648Sandrew	btinfo.bt_gpio_bt_priority = 7;
105266648Sandrew	btinfo.bt_gpio_wlan_active = 5;
106266648Sandrew	btinfo.bt_active_polarity = 1;	/* XXX not used */
107266648Sandrew	btinfo.bt_single_ant = 1;	/* 1 antenna on ar9285 ? */
108239281Sgonzo	btinfo.bt_isolation = 0;	/* in dB, not used */
109239281Sgonzo
110239281Sgonzo	ath_hal_btcoex_set_info(ah, &btinfo);
111239281Sgonzo
112239281Sgonzo	btconfig.bt_time_extend = 0;
113239281Sgonzo	btconfig.bt_txstate_extend = 1;	/* true */
114239281Sgonzo	btconfig.bt_txframe_extend = 1;	/* true */
115239281Sgonzo	btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED;
116239281Sgonzo	btconfig.bt_quiet_collision = 1;	/* true */
117239281Sgonzo	btconfig.bt_rxclear_polarity = 1;	/* true */
118239281Sgonzo	btconfig.bt_priority_time = 2;
119239281Sgonzo	btconfig.bt_first_slot_time = 5;
120239281Sgonzo	btconfig.bt_hold_rxclear = 1;	/* true */
121239281Sgonzo
122239281Sgonzo	ath_hal_btcoex_set_config(ah, &btconfig);
123239281Sgonzo
124239281Sgonzo	/*
125239281Sgonzo	 * Enable antenna diversity.
126239281Sgonzo	 */
127239281Sgonzo	ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1);
128239281Sgonzo
129239281Sgonzo	return (0);
130239281Sgonzo}
131239281Sgonzo
132239281Sgonzo/*
133239281Sgonzo * Initial AR9485 / (WB225) bluetooth coexistence settings,
134239281Sgonzo * just for experimentation.
135239281Sgonzo *
136239281Sgonzo * Return 0 for OK; errno for error.
137239281Sgonzo */
138239281Sgonzostatic int
139239281Sgonzoath_btcoex_cfg_wb225(struct ath_softc *sc)
140239281Sgonzo{
141239281Sgonzo	HAL_BT_COEX_INFO btinfo;
142239281Sgonzo	HAL_BT_COEX_CONFIG btconfig;
143239281Sgonzo	struct ath_hal *ah = sc->sc_ah;
144239281Sgonzo
145239281Sgonzo	if (! ath_hal_btcoex_supported(ah))
146239281Sgonzo		return (EINVAL);
147239281Sgonzo
148239281Sgonzo	bzero(&btinfo, sizeof(btinfo));
149239281Sgonzo	bzero(&btconfig, sizeof(btconfig));
150239281Sgonzo
151239281Sgonzo	device_printf(sc->sc_dev, "Enabling WB225 BTCOEX\n");
152239281Sgonzo
153239281Sgonzo	btinfo.bt_module = HAL_BT_MODULE_JANUS;	/* XXX not used? */
154239281Sgonzo	btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE;
155239281Sgonzo	/*
156239281Sgonzo	 * These are the three GPIO pins hooked up between the AR9485 and
157239281Sgonzo	 * the bluetooth module.
158239281Sgonzo	 */
159239281Sgonzo	btinfo.bt_gpio_bt_active = 4;
160239281Sgonzo	btinfo.bt_gpio_bt_priority = 8;
161239281Sgonzo	btinfo.bt_gpio_wlan_active = 5;
162239281Sgonzo
163239281Sgonzo	btinfo.bt_active_polarity = 1;	/* XXX not used */
164239281Sgonzo	btinfo.bt_single_ant = 1;	/* 1 antenna on ar9285 ? */
165239281Sgonzo	btinfo.bt_isolation = 0;	/* in dB, not used */
166239281Sgonzo
167239281Sgonzo	ath_hal_btcoex_set_info(ah, &btinfo);
168239281Sgonzo
169239281Sgonzo	btconfig.bt_time_extend = 0;
170239281Sgonzo	btconfig.bt_txstate_extend = 1;	/* true */
171239281Sgonzo	btconfig.bt_txframe_extend = 1;	/* true */
172239281Sgonzo	btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED;
173239281Sgonzo	btconfig.bt_quiet_collision = 1;	/* true */
174239281Sgonzo	btconfig.bt_rxclear_polarity = 1;	/* true */
175239281Sgonzo	btconfig.bt_priority_time = 2;
176239281Sgonzo	btconfig.bt_first_slot_time = 5;
177239281Sgonzo	btconfig.bt_hold_rxclear = 1;	/* true */
178239281Sgonzo
179239281Sgonzo	ath_hal_btcoex_set_config(ah, &btconfig);
180239281Sgonzo
181239281Sgonzo	/*
182239281Sgonzo	 * Enable antenna diversity.
183239281Sgonzo	 */
184239281Sgonzo	ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1);
185239281Sgonzo
186239281Sgonzo	return (0);
187239281Sgonzo}
188239281Sgonzo
189239281Sgonzo
190239281Sgonzo#if 0
191239281Sgonzo/*
192239281Sgonzo * When using bluetooth coexistence, ASPM needs to be disabled
193239281Sgonzo * otherwise the sleeping interferes with the bluetooth (USB)
194239281Sgonzo * operation and the MAC sleep/wakeup hardware.
195239281Sgonzo *
196239281Sgonzo * The PCIe powersave routine also needs to not be called
197239281Sgonzo * by the driver during suspend/resume, else things will get
198239281Sgonzo * a little odd.  Check Linux ath9k for more details.
199239281Sgonzo */
200239281Sgonzostatic int
201239281Sgonzoath_btcoex_aspm_wb195(struct ath_softc *sc)
202239281Sgonzo{
203239281Sgonzo
204239281Sgonzo	/* XXX TODO: clear device ASPM L0S and L1 */
205239281Sgonzo	/* XXX TODO: clear _parent_ ASPM L0S and L1 */
206239281Sgonzo}
207239281Sgonzo#endif
208239281Sgonzo
209239281Sgonzo/*
210239281Sgonzo * Methods which are required
211239281Sgonzo */
212239281Sgonzo
213239281Sgonzo/*
214239281Sgonzo * Attach btcoex to the given interface
215239281Sgonzo */
216239281Sgonzoint
217239281Sgonzoath_btcoex_attach(struct ath_softc *sc)
218239281Sgonzo{
219239281Sgonzo	int ret;
220239281Sgonzo	struct ath_hal *ah = sc->sc_ah;
221239281Sgonzo	const char *profname;
222239281Sgonzo
223239281Sgonzo	/*
224239281Sgonzo	 * No chipset bluetooth coexistence? Then do nothing.
225239281Sgonzo	 */
226239281Sgonzo	if (! ath_hal_btcoex_supported(ah))
227239281Sgonzo		return (0);
228239281Sgonzo
229239281Sgonzo	/*
230239281Sgonzo	 * Look at the hints to determine which bluetooth
231239281Sgonzo	 * profile to configure.
232239281Sgonzo	 */
233239281Sgonzo	ret = resource_string_value(device_get_name(sc->sc_dev),
234239281Sgonzo	    device_get_unit(sc->sc_dev),
235239281Sgonzo	    "btcoex_profile",
236239281Sgonzo	    &profname);
237239281Sgonzo	if (ret != 0) {
238239281Sgonzo		/* nothing to do */
239239281Sgonzo		return (0);
240239281Sgonzo	}
241239281Sgonzo
242239281Sgonzo	if (strncmp(profname, "wb195", 5) == 0) {
243239281Sgonzo		ret = ath_btcoex_cfg_wb195(sc);
244239281Sgonzo	} else if (strncmp(profname, "wb225", 5) == 0) {
245239281Sgonzo		ret = ath_btcoex_cfg_wb225(sc);
246239281Sgonzo	} else {
247239281Sgonzo		return (0);
248239281Sgonzo	}
249239281Sgonzo
250239281Sgonzo	/*
251239281Sgonzo	 * Propagate up failure from the actual attach phase.
252239281Sgonzo	 */
253239281Sgonzo	if (ret != 0)
254239281Sgonzo		return (ret);
255239281Sgonzo
256239281Sgonzo	return (0);
257239281Sgonzo}
258239281Sgonzo
259239281Sgonzo/*
260239281Sgonzo * Detach btcoex from the given interface
261239281Sgonzo */
262239281Sgonzoint
263239281Sgonzoath_btcoex_detach(struct ath_softc *sc)
264239281Sgonzo{
265239281Sgonzo
266239281Sgonzo	return (0);
267239281Sgonzo}
268239281Sgonzo
269239281Sgonzo/*
270239281Sgonzo * Configure or disable bluetooth coexistence on the given channel.
271239281Sgonzo *
272239281Sgonzo * For AR9285/AR9287/AR9485, we'll never see a 5GHz channel, so we just
273239281Sgonzo * assume bluetooth coexistence is always on.
274239281Sgonzo *
275239281Sgonzo * For AR9462, we may see a 5GHz channel; bluetooth coexistence should
276239281Sgonzo * not be enabled on those channels.
277239281Sgonzo */
278239281Sgonzoint
279239281Sgonzoath_btcoex_enable(struct ath_softc *sc, const struct ieee80211_channel *chan)
280239281Sgonzo{
281239281Sgonzo
282239281Sgonzo	return (0);
283239281Sgonzo}
284239281Sgonzo
285239281Sgonzo/*
286284532Sgonzo * Handle ioctl requests from the diagnostic interface.
287239281Sgonzo *
288239281Sgonzo * The initial part of this code resembles ath_ioctl_diag();
289239281Sgonzo * it's likely a good idea to reduce duplication between
290239281Sgonzo * these two routines.
291239281Sgonzo */
292239281Sgonzoint
293239281Sgonzoath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad)
294239281Sgonzo{
295239281Sgonzo	unsigned int id = ad->ad_id & ATH_DIAG_ID;
296239281Sgonzo	void *indata = NULL;
297239281Sgonzo	void *outdata = NULL;
298239281Sgonzo	u_int32_t insize = ad->ad_in_size;
299239281Sgonzo	u_int32_t outsize = ad->ad_out_size;
300239281Sgonzo	int error = 0;
301239281Sgonzo//	int val;
302239281Sgonzo
303239281Sgonzo	if (ad->ad_id & ATH_DIAG_IN) {
304239281Sgonzo		/*
305239281Sgonzo		 * Copy in data.
306239281Sgonzo		 */
307239281Sgonzo		indata = malloc(insize, M_TEMP, M_NOWAIT);
308239281Sgonzo		if (indata == NULL) {
309239281Sgonzo			error = ENOMEM;
310239281Sgonzo			goto bad;
311239281Sgonzo		}
312239281Sgonzo		error = copyin(ad->ad_in_data, indata, insize);
313239281Sgonzo		if (error)
314239281Sgonzo			goto bad;
315239281Sgonzo	}
316239281Sgonzo	if (ad->ad_id & ATH_DIAG_DYN) {
317239281Sgonzo		/*
318239281Sgonzo		 * Allocate a buffer for the results (otherwise the HAL
319239281Sgonzo		 * returns a pointer to a buffer where we can read the
320284532Sgonzo		 * results).  Note that we depend on the HAL leaving this
321239281Sgonzo		 * pointer for us to use below in reclaiming the buffer;
322239281Sgonzo		 * may want to be more defensive.
323284532Sgonzo		 */
324284532Sgonzo		outdata = malloc(outsize, M_TEMP, M_NOWAIT | M_ZERO);
325284532Sgonzo		if (outdata == NULL) {
326284532Sgonzo			error = ENOMEM;
327284532Sgonzo			goto bad;
328284532Sgonzo		}
329284532Sgonzo	}
330284532Sgonzo	switch (id) {
331284532Sgonzo		default:
332284532Sgonzo			error = EINVAL;
333284532Sgonzo			goto bad;
334284532Sgonzo	}
335284532Sgonzo	if (outsize < ad->ad_out_size)
336284532Sgonzo		ad->ad_out_size = outsize;
337284532Sgonzo	if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size))
338284532Sgonzo		error = EFAULT;
339284532Sgonzobad:
340284532Sgonzo	if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL)
341284532Sgonzo		free(indata, M_TEMP);
342284532Sgonzo	if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL)
343284532Sgonzo		free(outdata, M_TEMP);
344284532Sgonzo	return (error);
345284532Sgonzo}
346284532Sgonzo
347284532Sgonzo