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