if_ath_btcoex.c revision 277277
1251487Sadrian/*- 2251487Sadrian * Copyright (c) 2013 Adrian Chadd <adrian@FreeBSD.org> 3251487Sadrian * All rights reserved. 4251487Sadrian * 5251487Sadrian * Redistribution and use in source and binary forms, with or without 6251487Sadrian * modification, are permitted provided that the following conditions 7251487Sadrian * are met: 8251487Sadrian * 1. Redistributions of source code must retain the above copyright 9251487Sadrian * notice, this list of conditions and the following disclaimer, 10251487Sadrian * without modification. 11251487Sadrian * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12251487Sadrian * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13251487Sadrian * redistribution must be conditioned upon including a substantially 14251487Sadrian * similar Disclaimer requirement for further binary redistribution. 15251487Sadrian * 16251487Sadrian * NO WARRANTY 17251487Sadrian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18251487Sadrian * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19251487Sadrian * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20251487Sadrian * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21251487Sadrian * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22251487Sadrian * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23251487Sadrian * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24251487Sadrian * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25251487Sadrian * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26251487Sadrian * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27251487Sadrian * THE POSSIBILITY OF SUCH DAMAGES. 28251487Sadrian * 29251487Sadrian * $FreeBSD: head/sys/dev/ath/if_ath_btcoex.c 277277 2015-01-17 00:02:18Z adrian $ 30251487Sadrian */ 31251487Sadrian#include <sys/cdefs.h> 32251487Sadrian__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_btcoex.c 277277 2015-01-17 00:02:18Z adrian $"); 33251487Sadrian 34251487Sadrian/* 35251487Sadrian * This implements some very basic bluetooth coexistence methods for 36251487Sadrian * the ath(4) hardware. 37251487Sadrian */ 38251487Sadrian#include "opt_ath.h" 39251487Sadrian#include "opt_inet.h" 40251487Sadrian#include "opt_wlan.h" 41251487Sadrian 42251487Sadrian#include <sys/param.h> 43251487Sadrian#include <sys/systm.h> 44251487Sadrian#include <sys/sysctl.h> 45251487Sadrian#include <sys/kernel.h> 46251487Sadrian#include <sys/lock.h> 47257176Sglebius#include <sys/malloc.h> 48251487Sadrian#include <sys/mutex.h> 49251487Sadrian#include <sys/errno.h> 50251487Sadrian 51251487Sadrian#include <machine/bus.h> 52251487Sadrian#include <machine/resource.h> 53251487Sadrian#include <sys/bus.h> 54251487Sadrian 55251487Sadrian#include <sys/socket.h> 56251487Sadrian 57251487Sadrian#include <net/if.h> 58257176Sglebius#include <net/if_var.h> 59251487Sadrian#include <net/if_media.h> 60251487Sadrian#include <net/if_arp.h> 61251487Sadrian#include <net/ethernet.h> /* XXX for ether_sprintf */ 62251487Sadrian 63251487Sadrian#include <net80211/ieee80211_var.h> 64251487Sadrian 65251487Sadrian#include <net/bpf.h> 66251487Sadrian 67251487Sadrian#ifdef INET 68251487Sadrian#include <netinet/in.h> 69251487Sadrian#include <netinet/if_ether.h> 70251487Sadrian#endif 71251487Sadrian 72251487Sadrian#include <dev/ath/if_athvar.h> 73251487Sadrian#include <dev/ath/if_ath_btcoex.h> 74251487Sadrian 75251487Sadrian/* 76251487Sadrian * Initial AR9285 / (WB195) bluetooth coexistence settings, 77251487Sadrian * just for experimentation. 78251487Sadrian * 79251487Sadrian * Return 0 for OK; errno for error. 80251487Sadrian * 81251487Sadrian * XXX TODO: There needs to be a PCIe workaround to disable ASPM if 82251487Sadrian * bluetooth coexistence is enabled. 83251487Sadrian */ 84251487Sadrianstatic int 85251487Sadrianath_btcoex_cfg_wb195(struct ath_softc *sc) 86251487Sadrian{ 87251487Sadrian HAL_BT_COEX_INFO btinfo; 88251487Sadrian HAL_BT_COEX_CONFIG btconfig; 89251487Sadrian struct ath_hal *ah = sc->sc_ah; 90251487Sadrian 91251487Sadrian if (! ath_hal_btcoex_supported(ah)) 92251487Sadrian return (EINVAL); 93251487Sadrian 94251487Sadrian bzero(&btinfo, sizeof(btinfo)); 95251487Sadrian bzero(&btconfig, sizeof(btconfig)); 96251487Sadrian 97251487Sadrian device_printf(sc->sc_dev, "Enabling WB195 BTCOEX\n"); 98251487Sadrian 99251487Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; 100251487Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE; 101251487Sadrian /* 102251487Sadrian * These are the three GPIO pins hooked up between the AR9285 and 103251487Sadrian * the AR3011. 104251487Sadrian */ 105251487Sadrian btinfo.bt_gpio_bt_active = 6; 106251487Sadrian btinfo.bt_gpio_bt_priority = 7; 107251487Sadrian btinfo.bt_gpio_wlan_active = 5; 108251487Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 109251487Sadrian btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */ 110251487Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 111251487Sadrian 112251487Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 113251487Sadrian 114251487Sadrian btconfig.bt_time_extend = 0; 115251487Sadrian btconfig.bt_txstate_extend = 1; /* true */ 116251487Sadrian btconfig.bt_txframe_extend = 1; /* true */ 117251487Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 118251487Sadrian btconfig.bt_quiet_collision = 1; /* true */ 119251487Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 120251487Sadrian btconfig.bt_priority_time = 2; 121251487Sadrian btconfig.bt_first_slot_time = 5; 122251487Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 123251487Sadrian 124251487Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 125251487Sadrian 126251487Sadrian /* 127251487Sadrian * Enable antenna diversity. 128251487Sadrian */ 129251487Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 130251487Sadrian 131251487Sadrian return (0); 132251487Sadrian} 133251487Sadrian 134251742Sadrian/* 135251742Sadrian * Initial AR9485 / (WB225) bluetooth coexistence settings, 136251742Sadrian * just for experimentation. 137251742Sadrian * 138251742Sadrian * Return 0 for OK; errno for error. 139251742Sadrian */ 140251742Sadrianstatic int 141251742Sadrianath_btcoex_cfg_wb225(struct ath_softc *sc) 142251742Sadrian{ 143251742Sadrian HAL_BT_COEX_INFO btinfo; 144251742Sadrian HAL_BT_COEX_CONFIG btconfig; 145251742Sadrian struct ath_hal *ah = sc->sc_ah; 146251742Sadrian 147251742Sadrian if (! ath_hal_btcoex_supported(ah)) 148251742Sadrian return (EINVAL); 149251742Sadrian 150251742Sadrian bzero(&btinfo, sizeof(btinfo)); 151251742Sadrian bzero(&btconfig, sizeof(btconfig)); 152251742Sadrian 153251742Sadrian device_printf(sc->sc_dev, "Enabling WB225 BTCOEX\n"); 154251742Sadrian 155251742Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */ 156251742Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE; 157251742Sadrian /* 158251742Sadrian * These are the three GPIO pins hooked up between the AR9485 and 159251742Sadrian * the bluetooth module. 160251742Sadrian */ 161251742Sadrian btinfo.bt_gpio_bt_active = 4; 162251742Sadrian btinfo.bt_gpio_bt_priority = 8; 163251742Sadrian btinfo.bt_gpio_wlan_active = 5; 164251742Sadrian 165251742Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 166251742Sadrian btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */ 167251742Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 168251742Sadrian 169251742Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 170251742Sadrian 171251742Sadrian btconfig.bt_time_extend = 0; 172251742Sadrian btconfig.bt_txstate_extend = 1; /* true */ 173251742Sadrian btconfig.bt_txframe_extend = 1; /* true */ 174251742Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 175251742Sadrian btconfig.bt_quiet_collision = 1; /* true */ 176251742Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 177251742Sadrian btconfig.bt_priority_time = 2; 178251742Sadrian btconfig.bt_first_slot_time = 5; 179251742Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 180251742Sadrian 181251742Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 182251742Sadrian 183251742Sadrian /* 184251742Sadrian * Enable antenna diversity. 185251742Sadrian */ 186251742Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 187251742Sadrian 188251742Sadrian return (0); 189251742Sadrian} 190251742Sadrian 191277277Sadrian/* 192277277Sadrian * Initial AR9462 / (WB222) bluetooth coexistence settings, 193277277Sadrian * just for experimentation. 194277277Sadrian * 195277277Sadrian * Return 0 for OK; errno for error. 196277277Sadrian */ 197277277Sadrianstatic int 198277277Sadrianath_btcoex_cfg_wb222(struct ath_softc *sc) 199277277Sadrian{ 200277277Sadrian HAL_BT_COEX_INFO btinfo; 201277277Sadrian HAL_BT_COEX_CONFIG btconfig; 202277277Sadrian struct ath_hal *ah = sc->sc_ah; 203251742Sadrian 204277277Sadrian if (! ath_hal_btcoex_supported(ah)) 205277277Sadrian return (EINVAL); 206277277Sadrian 207277277Sadrian bzero(&btinfo, sizeof(btinfo)); 208277277Sadrian bzero(&btconfig, sizeof(btconfig)); 209277277Sadrian 210277277Sadrian device_printf(sc->sc_dev, "Enabling WB222 BTCOEX\n"); 211277277Sadrian 212277277Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */ 213277277Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_MCI; 214277277Sadrian 215277277Sadrian /* 216277277Sadrian * MCI uses a completely different interface to speak 217277277Sadrian * to the bluetooth module - it's a command based 218277277Sadrian * thing over a serial line, rather than 219277277Sadrian * state pins to/from the bluetooth module. 220277277Sadrian * 221277277Sadrian * So, the GPIO configuration, polarity, etc 222277277Sadrian * doesn't matter on MCI devices; it's just 223277277Sadrian * completely ignored by the HAL. 224277277Sadrian */ 225277277Sadrian btinfo.bt_gpio_bt_active = 4; 226277277Sadrian btinfo.bt_gpio_bt_priority = 8; 227277277Sadrian btinfo.bt_gpio_wlan_active = 5; 228277277Sadrian 229277277Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 230277277Sadrian btinfo.bt_single_ant = 0; /* 2 antenna on WB222 */ 231277277Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 232277277Sadrian 233277277Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 234277277Sadrian 235277277Sadrian btconfig.bt_time_extend = 0; 236277277Sadrian btconfig.bt_txstate_extend = 1; /* true */ 237277277Sadrian btconfig.bt_txframe_extend = 1; /* true */ 238277277Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 239277277Sadrian btconfig.bt_quiet_collision = 1; /* true */ 240277277Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 241277277Sadrian btconfig.bt_priority_time = 2; 242277277Sadrian btconfig.bt_first_slot_time = 5; 243277277Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 244277277Sadrian 245277277Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 246277277Sadrian 247277277Sadrian /* 248277277Sadrian * Enable antenna diversity. 249277277Sadrian */ 250277277Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 251277277Sadrian 252277277Sadrian return (0); 253277277Sadrian} 254277277Sadrian 255277277Sadrian 256277277Sadrian 257277277Sadrian 258251487Sadrian#if 0 259251487Sadrian/* 260251487Sadrian * When using bluetooth coexistence, ASPM needs to be disabled 261251487Sadrian * otherwise the sleeping interferes with the bluetooth (USB) 262251487Sadrian * operation and the MAC sleep/wakeup hardware. 263251606Sadrian * 264251606Sadrian * The PCIe powersave routine also needs to not be called 265251606Sadrian * by the driver during suspend/resume, else things will get 266251606Sadrian * a little odd. Check Linux ath9k for more details. 267251487Sadrian */ 268251487Sadrianstatic int 269251487Sadrianath_btcoex_aspm_wb195(struct ath_softc *sc) 270251487Sadrian{ 271251487Sadrian 272251487Sadrian /* XXX TODO: clear device ASPM L0S and L1 */ 273251487Sadrian /* XXX TODO: clear _parent_ ASPM L0S and L1 */ 274251487Sadrian} 275251487Sadrian#endif 276251487Sadrian 277251487Sadrian/* 278251487Sadrian * Methods which are required 279251487Sadrian */ 280251487Sadrian 281251487Sadrian/* 282251487Sadrian * Attach btcoex to the given interface 283251487Sadrian */ 284251487Sadrianint 285251487Sadrianath_btcoex_attach(struct ath_softc *sc) 286251487Sadrian{ 287251487Sadrian int ret; 288251487Sadrian struct ath_hal *ah = sc->sc_ah; 289251487Sadrian const char *profname; 290251487Sadrian 291251487Sadrian /* 292251487Sadrian * No chipset bluetooth coexistence? Then do nothing. 293251487Sadrian */ 294251487Sadrian if (! ath_hal_btcoex_supported(ah)) 295251487Sadrian return (0); 296251487Sadrian 297251487Sadrian /* 298251487Sadrian * Look at the hints to determine which bluetooth 299251487Sadrian * profile to configure. 300251487Sadrian */ 301251487Sadrian ret = resource_string_value(device_get_name(sc->sc_dev), 302251487Sadrian device_get_unit(sc->sc_dev), 303251487Sadrian "btcoex_profile", 304251487Sadrian &profname); 305251487Sadrian if (ret != 0) { 306251487Sadrian /* nothing to do */ 307251487Sadrian return (0); 308251487Sadrian } 309251487Sadrian 310251487Sadrian if (strncmp(profname, "wb195", 5) == 0) { 311251487Sadrian ret = ath_btcoex_cfg_wb195(sc); 312277277Sadrian } else if (strncmp(profname, "wb222", 5) == 0) { 313277277Sadrian ret = ath_btcoex_cfg_wb222(sc); 314251742Sadrian } else if (strncmp(profname, "wb225", 5) == 0) { 315251742Sadrian ret = ath_btcoex_cfg_wb225(sc); 316251487Sadrian } else { 317251487Sadrian return (0); 318251487Sadrian } 319251487Sadrian 320251487Sadrian /* 321251487Sadrian * Propagate up failure from the actual attach phase. 322251487Sadrian */ 323251487Sadrian if (ret != 0) 324251487Sadrian return (ret); 325251487Sadrian 326251487Sadrian return (0); 327251487Sadrian} 328251487Sadrian 329251487Sadrian/* 330251487Sadrian * Detach btcoex from the given interface 331251487Sadrian */ 332251487Sadrianint 333251487Sadrianath_btcoex_detach(struct ath_softc *sc) 334251487Sadrian{ 335251487Sadrian 336251487Sadrian return (0); 337251487Sadrian} 338251487Sadrian 339251487Sadrian/* 340251487Sadrian * Configure or disable bluetooth coexistence on the given channel. 341251487Sadrian * 342251487Sadrian * For AR9285/AR9287/AR9485, we'll never see a 5GHz channel, so we just 343251487Sadrian * assume bluetooth coexistence is always on. 344251487Sadrian * 345251487Sadrian * For AR9462, we may see a 5GHz channel; bluetooth coexistence should 346251487Sadrian * not be enabled on those channels. 347251487Sadrian */ 348251487Sadrianint 349251487Sadrianath_btcoex_enable(struct ath_softc *sc, const struct ieee80211_channel *chan) 350251487Sadrian{ 351251487Sadrian 352251487Sadrian return (0); 353251487Sadrian} 354251487Sadrian 355251487Sadrian/* 356251487Sadrian * Handle ioctl requests from the diagnostic interface. 357251487Sadrian * 358251487Sadrian * The initial part of this code resembles ath_ioctl_diag(); 359251487Sadrian * it's likely a good idea to reduce duplication between 360251487Sadrian * these two routines. 361251487Sadrian */ 362251487Sadrianint 363251487Sadrianath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad) 364251487Sadrian{ 365251487Sadrian unsigned int id = ad->ad_id & ATH_DIAG_ID; 366251487Sadrian void *indata = NULL; 367251487Sadrian void *outdata = NULL; 368251487Sadrian u_int32_t insize = ad->ad_in_size; 369251487Sadrian u_int32_t outsize = ad->ad_out_size; 370251487Sadrian int error = 0; 371251487Sadrian// int val; 372251487Sadrian 373251487Sadrian if (ad->ad_id & ATH_DIAG_IN) { 374251487Sadrian /* 375251487Sadrian * Copy in data. 376251487Sadrian */ 377251487Sadrian indata = malloc(insize, M_TEMP, M_NOWAIT); 378251487Sadrian if (indata == NULL) { 379251487Sadrian error = ENOMEM; 380251487Sadrian goto bad; 381251487Sadrian } 382251487Sadrian error = copyin(ad->ad_in_data, indata, insize); 383251487Sadrian if (error) 384251487Sadrian goto bad; 385251487Sadrian } 386251487Sadrian if (ad->ad_id & ATH_DIAG_DYN) { 387251487Sadrian /* 388251487Sadrian * Allocate a buffer for the results (otherwise the HAL 389251487Sadrian * returns a pointer to a buffer where we can read the 390251487Sadrian * results). Note that we depend on the HAL leaving this 391251487Sadrian * pointer for us to use below in reclaiming the buffer; 392251487Sadrian * may want to be more defensive. 393251487Sadrian */ 394251487Sadrian outdata = malloc(outsize, M_TEMP, M_NOWAIT); 395251487Sadrian if (outdata == NULL) { 396251487Sadrian error = ENOMEM; 397251487Sadrian goto bad; 398251487Sadrian } 399251487Sadrian } 400251487Sadrian switch (id) { 401251487Sadrian default: 402251487Sadrian error = EINVAL; 403251487Sadrian } 404251487Sadrian if (outsize < ad->ad_out_size) 405251487Sadrian ad->ad_out_size = outsize; 406251487Sadrian if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size)) 407251487Sadrian error = EFAULT; 408251487Sadrianbad: 409251487Sadrian if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) 410251487Sadrian free(indata, M_TEMP); 411251487Sadrian if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) 412251487Sadrian free(outdata, M_TEMP); 413251487Sadrian return (error); 414251487Sadrian} 415251487Sadrian 416