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$ 30251487Sadrian */ 31251487Sadrian#include <sys/cdefs.h> 32251487Sadrian__FBSDID("$FreeBSD$"); 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> 47251487Sadrian#include <sys/mutex.h> 48251487Sadrian#include <sys/errno.h> 49251487Sadrian 50251487Sadrian#include <machine/bus.h> 51251487Sadrian#include <machine/resource.h> 52251487Sadrian#include <sys/bus.h> 53251487Sadrian 54251487Sadrian#include <sys/socket.h> 55251487Sadrian 56251487Sadrian#include <net/if.h> 57251487Sadrian#include <net/if_media.h> 58251487Sadrian#include <net/if_arp.h> 59251487Sadrian#include <net/ethernet.h> /* XXX for ether_sprintf */ 60251487Sadrian 61251487Sadrian#include <net80211/ieee80211_var.h> 62251487Sadrian 63251487Sadrian#include <net/bpf.h> 64251487Sadrian 65251487Sadrian#ifdef INET 66251487Sadrian#include <netinet/in.h> 67251487Sadrian#include <netinet/if_ether.h> 68251487Sadrian#endif 69251487Sadrian 70251487Sadrian#include <dev/ath/if_athvar.h> 71251487Sadrian#include <dev/ath/if_ath_btcoex.h> 72251487Sadrian 73251487Sadrian/* 74251487Sadrian * Initial AR9285 / (WB195) bluetooth coexistence settings, 75251487Sadrian * just for experimentation. 76251487Sadrian * 77251487Sadrian * Return 0 for OK; errno for error. 78251487Sadrian * 79251487Sadrian * XXX TODO: There needs to be a PCIe workaround to disable ASPM if 80251487Sadrian * bluetooth coexistence is enabled. 81251487Sadrian */ 82251487Sadrianstatic int 83251487Sadrianath_btcoex_cfg_wb195(struct ath_softc *sc) 84251487Sadrian{ 85251487Sadrian HAL_BT_COEX_INFO btinfo; 86251487Sadrian HAL_BT_COEX_CONFIG btconfig; 87251487Sadrian struct ath_hal *ah = sc->sc_ah; 88251487Sadrian 89251487Sadrian if (! ath_hal_btcoex_supported(ah)) 90251487Sadrian return (EINVAL); 91251487Sadrian 92251487Sadrian bzero(&btinfo, sizeof(btinfo)); 93251487Sadrian bzero(&btconfig, sizeof(btconfig)); 94251487Sadrian 95251487Sadrian device_printf(sc->sc_dev, "Enabling WB195 BTCOEX\n"); 96251487Sadrian 97251487Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; 98251487Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE; 99251487Sadrian /* 100251487Sadrian * These are the three GPIO pins hooked up between the AR9285 and 101251487Sadrian * the AR3011. 102251487Sadrian */ 103251487Sadrian btinfo.bt_gpio_bt_active = 6; 104251487Sadrian btinfo.bt_gpio_bt_priority = 7; 105251487Sadrian btinfo.bt_gpio_wlan_active = 5; 106251487Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 107251487Sadrian btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */ 108251487Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 109251487Sadrian 110251487Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 111251487Sadrian 112251487Sadrian btconfig.bt_time_extend = 0; 113251487Sadrian btconfig.bt_txstate_extend = 1; /* true */ 114251487Sadrian btconfig.bt_txframe_extend = 1; /* true */ 115251487Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 116251487Sadrian btconfig.bt_quiet_collision = 1; /* true */ 117251487Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 118251487Sadrian btconfig.bt_priority_time = 2; 119251487Sadrian btconfig.bt_first_slot_time = 5; 120251487Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 121251487Sadrian 122251487Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 123251487Sadrian 124251487Sadrian /* 125251487Sadrian * Enable antenna diversity. 126251487Sadrian */ 127251487Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 128251487Sadrian 129251487Sadrian return (0); 130251487Sadrian} 131251487Sadrian 132251742Sadrian/* 133251742Sadrian * Initial AR9485 / (WB225) bluetooth coexistence settings, 134251742Sadrian * just for experimentation. 135251742Sadrian * 136251742Sadrian * Return 0 for OK; errno for error. 137251742Sadrian */ 138251742Sadrianstatic int 139251742Sadrianath_btcoex_cfg_wb225(struct ath_softc *sc) 140251742Sadrian{ 141251742Sadrian HAL_BT_COEX_INFO btinfo; 142251742Sadrian HAL_BT_COEX_CONFIG btconfig; 143251742Sadrian struct ath_hal *ah = sc->sc_ah; 144251742Sadrian 145251742Sadrian if (! ath_hal_btcoex_supported(ah)) 146251742Sadrian return (EINVAL); 147251742Sadrian 148251742Sadrian bzero(&btinfo, sizeof(btinfo)); 149251742Sadrian bzero(&btconfig, sizeof(btconfig)); 150251742Sadrian 151251742Sadrian device_printf(sc->sc_dev, "Enabling WB225 BTCOEX\n"); 152251742Sadrian 153251742Sadrian btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */ 154251742Sadrian btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE; 155251742Sadrian /* 156251742Sadrian * These are the three GPIO pins hooked up between the AR9485 and 157251742Sadrian * the bluetooth module. 158251742Sadrian */ 159251742Sadrian btinfo.bt_gpio_bt_active = 4; 160251742Sadrian btinfo.bt_gpio_bt_priority = 8; 161251742Sadrian btinfo.bt_gpio_wlan_active = 5; 162251742Sadrian 163251742Sadrian btinfo.bt_active_polarity = 1; /* XXX not used */ 164251742Sadrian btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */ 165251742Sadrian btinfo.bt_isolation = 0; /* in dB, not used */ 166251742Sadrian 167251742Sadrian ath_hal_btcoex_set_info(ah, &btinfo); 168251742Sadrian 169251742Sadrian btconfig.bt_time_extend = 0; 170251742Sadrian btconfig.bt_txstate_extend = 1; /* true */ 171251742Sadrian btconfig.bt_txframe_extend = 1; /* true */ 172251742Sadrian btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 173251742Sadrian btconfig.bt_quiet_collision = 1; /* true */ 174251742Sadrian btconfig.bt_rxclear_polarity = 1; /* true */ 175251742Sadrian btconfig.bt_priority_time = 2; 176251742Sadrian btconfig.bt_first_slot_time = 5; 177251742Sadrian btconfig.bt_hold_rxclear = 1; /* true */ 178251742Sadrian 179251742Sadrian ath_hal_btcoex_set_config(ah, &btconfig); 180251742Sadrian 181251742Sadrian /* 182251742Sadrian * Enable antenna diversity. 183251742Sadrian */ 184251742Sadrian ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 185251742Sadrian 186251742Sadrian return (0); 187251742Sadrian} 188251742Sadrian 189251742Sadrian 190251487Sadrian#if 0 191251487Sadrian/* 192251487Sadrian * When using bluetooth coexistence, ASPM needs to be disabled 193251487Sadrian * otherwise the sleeping interferes with the bluetooth (USB) 194251487Sadrian * operation and the MAC sleep/wakeup hardware. 195251606Sadrian * 196251606Sadrian * The PCIe powersave routine also needs to not be called 197251606Sadrian * by the driver during suspend/resume, else things will get 198251606Sadrian * a little odd. Check Linux ath9k for more details. 199251487Sadrian */ 200251487Sadrianstatic int 201251487Sadrianath_btcoex_aspm_wb195(struct ath_softc *sc) 202251487Sadrian{ 203251487Sadrian 204251487Sadrian /* XXX TODO: clear device ASPM L0S and L1 */ 205251487Sadrian /* XXX TODO: clear _parent_ ASPM L0S and L1 */ 206251487Sadrian} 207251487Sadrian#endif 208251487Sadrian 209251487Sadrian/* 210251487Sadrian * Methods which are required 211251487Sadrian */ 212251487Sadrian 213251487Sadrian/* 214251487Sadrian * Attach btcoex to the given interface 215251487Sadrian */ 216251487Sadrianint 217251487Sadrianath_btcoex_attach(struct ath_softc *sc) 218251487Sadrian{ 219251487Sadrian int ret; 220251487Sadrian struct ath_hal *ah = sc->sc_ah; 221251487Sadrian const char *profname; 222251487Sadrian 223251487Sadrian /* 224251487Sadrian * No chipset bluetooth coexistence? Then do nothing. 225251487Sadrian */ 226251487Sadrian if (! ath_hal_btcoex_supported(ah)) 227251487Sadrian return (0); 228251487Sadrian 229251487Sadrian /* 230251487Sadrian * Look at the hints to determine which bluetooth 231251487Sadrian * profile to configure. 232251487Sadrian */ 233251487Sadrian ret = resource_string_value(device_get_name(sc->sc_dev), 234251487Sadrian device_get_unit(sc->sc_dev), 235251487Sadrian "btcoex_profile", 236251487Sadrian &profname); 237251487Sadrian if (ret != 0) { 238251487Sadrian /* nothing to do */ 239251487Sadrian return (0); 240251487Sadrian } 241251487Sadrian 242251487Sadrian if (strncmp(profname, "wb195", 5) == 0) { 243251487Sadrian ret = ath_btcoex_cfg_wb195(sc); 244251742Sadrian } else if (strncmp(profname, "wb225", 5) == 0) { 245251742Sadrian ret = ath_btcoex_cfg_wb225(sc); 246251487Sadrian } else { 247251487Sadrian return (0); 248251487Sadrian } 249251487Sadrian 250251487Sadrian /* 251251487Sadrian * Propagate up failure from the actual attach phase. 252251487Sadrian */ 253251487Sadrian if (ret != 0) 254251487Sadrian return (ret); 255251487Sadrian 256251487Sadrian return (0); 257251487Sadrian} 258251487Sadrian 259251487Sadrian/* 260251487Sadrian * Detach btcoex from the given interface 261251487Sadrian */ 262251487Sadrianint 263251487Sadrianath_btcoex_detach(struct ath_softc *sc) 264251487Sadrian{ 265251487Sadrian 266251487Sadrian return (0); 267251487Sadrian} 268251487Sadrian 269251487Sadrian/* 270251487Sadrian * Configure or disable bluetooth coexistence on the given channel. 271251487Sadrian * 272251487Sadrian * For AR9285/AR9287/AR9485, we'll never see a 5GHz channel, so we just 273251487Sadrian * assume bluetooth coexistence is always on. 274251487Sadrian * 275251487Sadrian * For AR9462, we may see a 5GHz channel; bluetooth coexistence should 276251487Sadrian * not be enabled on those channels. 277251487Sadrian */ 278251487Sadrianint 279251487Sadrianath_btcoex_enable(struct ath_softc *sc, const struct ieee80211_channel *chan) 280251487Sadrian{ 281251487Sadrian 282251487Sadrian return (0); 283251487Sadrian} 284251487Sadrian 285251487Sadrian/* 286251487Sadrian * Handle ioctl requests from the diagnostic interface. 287251487Sadrian * 288251487Sadrian * The initial part of this code resembles ath_ioctl_diag(); 289251487Sadrian * it's likely a good idea to reduce duplication between 290251487Sadrian * these two routines. 291251487Sadrian */ 292251487Sadrianint 293251487Sadrianath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad) 294251487Sadrian{ 295251487Sadrian unsigned int id = ad->ad_id & ATH_DIAG_ID; 296251487Sadrian void *indata = NULL; 297251487Sadrian void *outdata = NULL; 298251487Sadrian u_int32_t insize = ad->ad_in_size; 299251487Sadrian u_int32_t outsize = ad->ad_out_size; 300251487Sadrian int error = 0; 301251487Sadrian// int val; 302251487Sadrian 303251487Sadrian if (ad->ad_id & ATH_DIAG_IN) { 304251487Sadrian /* 305251487Sadrian * Copy in data. 306251487Sadrian */ 307251487Sadrian indata = malloc(insize, M_TEMP, M_NOWAIT); 308251487Sadrian if (indata == NULL) { 309251487Sadrian error = ENOMEM; 310251487Sadrian goto bad; 311251487Sadrian } 312251487Sadrian error = copyin(ad->ad_in_data, indata, insize); 313251487Sadrian if (error) 314251487Sadrian goto bad; 315251487Sadrian } 316251487Sadrian if (ad->ad_id & ATH_DIAG_DYN) { 317251487Sadrian /* 318251487Sadrian * Allocate a buffer for the results (otherwise the HAL 319251487Sadrian * returns a pointer to a buffer where we can read the 320251487Sadrian * results). Note that we depend on the HAL leaving this 321251487Sadrian * pointer for us to use below in reclaiming the buffer; 322251487Sadrian * may want to be more defensive. 323251487Sadrian */ 324251487Sadrian outdata = malloc(outsize, M_TEMP, M_NOWAIT); 325251487Sadrian if (outdata == NULL) { 326251487Sadrian error = ENOMEM; 327251487Sadrian goto bad; 328251487Sadrian } 329251487Sadrian } 330251487Sadrian switch (id) { 331251487Sadrian default: 332251487Sadrian error = EINVAL; 333251487Sadrian } 334251487Sadrian if (outsize < ad->ad_out_size) 335251487Sadrian ad->ad_out_size = outsize; 336251487Sadrian if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size)) 337251487Sadrian error = EFAULT; 338251487Sadrianbad: 339251487Sadrian if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) 340251487Sadrian free(indata, M_TEMP); 341251487Sadrian if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) 342251487Sadrian free(outdata, M_TEMP); 343251487Sadrian return (error); 344251487Sadrian} 345251487Sadrian 346