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