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