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 51 #if defined(__DragonFly__) 52 /* empty */ 53 #else 54 #include <machine/bus.h> 55 #include <machine/resource.h> 56 #endif 57 #include <sys/bus.h> 58 59 #include <sys/socket.h> 60 61 #include <net/if.h> 62 #include <net/if_var.h> 63 #include <net/if_media.h> 64 #include <net/if_arp.h> 65 #include <net/ethernet.h> /* XXX for ether_sprintf */ 66 67 #include <netproto/802_11/ieee80211_var.h> 68 69 #include <net/bpf.h> 70 71 #ifdef INET 72 #include <netinet/in.h> 73 #include <netinet/if_ether.h> 74 #endif 75 76 #include <dev/netif/ath/ath/if_athvar.h> 77 #include <dev/netif/ath/ath/if_ath_btcoex.h> 78 79 /* 80 * Initial AR9285 / (WB195) bluetooth coexistence settings, 81 * just for experimentation. 82 * 83 * Return 0 for OK; errno for error. 84 * 85 * XXX TODO: There needs to be a PCIe workaround to disable ASPM if 86 * bluetooth coexistence is enabled. 87 */ 88 static int 89 ath_btcoex_cfg_wb195(struct ath_softc *sc) 90 { 91 HAL_BT_COEX_INFO btinfo; 92 HAL_BT_COEX_CONFIG btconfig; 93 struct ath_hal *ah = sc->sc_ah; 94 95 if (! ath_hal_btcoex_supported(ah)) 96 return (EINVAL); 97 98 bzero(&btinfo, sizeof(btinfo)); 99 bzero(&btconfig, sizeof(btconfig)); 100 101 device_printf(sc->sc_dev, "Enabling WB195 BTCOEX\n"); 102 103 btinfo.bt_module = HAL_BT_MODULE_JANUS; 104 btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE; 105 /* 106 * These are the three GPIO pins hooked up between the AR9285 and 107 * the AR3011. 108 */ 109 btinfo.bt_gpio_bt_active = 6; 110 btinfo.bt_gpio_bt_priority = 7; 111 btinfo.bt_gpio_wlan_active = 5; 112 btinfo.bt_active_polarity = 1; /* XXX not used */ 113 btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */ 114 btinfo.bt_isolation = 0; /* in dB, not used */ 115 116 ath_hal_btcoex_set_info(ah, &btinfo); 117 118 btconfig.bt_time_extend = 0; 119 btconfig.bt_txstate_extend = 1; /* true */ 120 btconfig.bt_txframe_extend = 1; /* true */ 121 btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 122 btconfig.bt_quiet_collision = 1; /* true */ 123 btconfig.bt_rxclear_polarity = 1; /* true */ 124 btconfig.bt_priority_time = 2; 125 btconfig.bt_first_slot_time = 5; 126 btconfig.bt_hold_rxclear = 1; /* true */ 127 128 ath_hal_btcoex_set_config(ah, &btconfig); 129 130 /* 131 * Enable antenna diversity. 132 */ 133 ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 134 135 return (0); 136 } 137 138 /* 139 * Initial AR9485 / (WB225) bluetooth coexistence settings, 140 * just for experimentation. 141 * 142 * Return 0 for OK; errno for error. 143 */ 144 static int 145 ath_btcoex_cfg_wb225(struct ath_softc *sc) 146 { 147 HAL_BT_COEX_INFO btinfo; 148 HAL_BT_COEX_CONFIG btconfig; 149 struct ath_hal *ah = sc->sc_ah; 150 151 if (! ath_hal_btcoex_supported(ah)) 152 return (EINVAL); 153 154 bzero(&btinfo, sizeof(btinfo)); 155 bzero(&btconfig, sizeof(btconfig)); 156 157 device_printf(sc->sc_dev, "Enabling WB225 BTCOEX\n"); 158 159 btinfo.bt_module = HAL_BT_MODULE_JANUS; /* XXX not used? */ 160 btinfo.bt_coex_config = HAL_BT_COEX_CFG_3WIRE; 161 /* 162 * These are the three GPIO pins hooked up between the AR9485 and 163 * the bluetooth module. 164 */ 165 btinfo.bt_gpio_bt_active = 4; 166 btinfo.bt_gpio_bt_priority = 8; 167 btinfo.bt_gpio_wlan_active = 5; 168 169 btinfo.bt_active_polarity = 1; /* XXX not used */ 170 btinfo.bt_single_ant = 1; /* 1 antenna on ar9285 ? */ 171 btinfo.bt_isolation = 0; /* in dB, not used */ 172 173 ath_hal_btcoex_set_info(ah, &btinfo); 174 175 btconfig.bt_time_extend = 0; 176 btconfig.bt_txstate_extend = 1; /* true */ 177 btconfig.bt_txframe_extend = 1; /* true */ 178 btconfig.bt_mode = HAL_BT_COEX_MODE_SLOTTED; 179 btconfig.bt_quiet_collision = 1; /* true */ 180 btconfig.bt_rxclear_polarity = 1; /* true */ 181 btconfig.bt_priority_time = 2; 182 btconfig.bt_first_slot_time = 5; 183 btconfig.bt_hold_rxclear = 1; /* true */ 184 185 ath_hal_btcoex_set_config(ah, &btconfig); 186 187 /* 188 * Enable antenna diversity. 189 */ 190 ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 191 192 return (0); 193 } 194 195 /* 196 * Initial AR9462 / (WB222) bluetooth coexistence settings, 197 * just for experimentation. 198 * 199 * Return 0 for OK; errno for error. 200 */ 201 static int 202 ath_btcoex_cfg_wb222(struct ath_softc *sc) 203 { 204 HAL_BT_COEX_INFO btinfo; 205 HAL_BT_COEX_CONFIG btconfig; 206 struct ath_hal *ah = sc->sc_ah; 207 208 if (! ath_hal_btcoex_supported(ah)) 209 return (EINVAL); 210 211 bzero(&btinfo, sizeof(btinfo)); 212 bzero(&btconfig, sizeof(btconfig)); 213 214 device_printf(sc->sc_dev, "Enabling WB222 BTCOEX\n"); 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 WB222 */ 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 /* 252 * Enable antenna diversity. 253 */ 254 ath_hal_btcoex_set_parameter(ah, HAL_BT_COEX_ANTENNA_DIVERSITY, 1); 255 256 return (0); 257 } 258 259 260 261 262 #if 0 263 /* 264 * When using bluetooth coexistence, ASPM needs to be disabled 265 * otherwise the sleeping interferes with the bluetooth (USB) 266 * operation and the MAC sleep/wakeup hardware. 267 * 268 * The PCIe powersave routine also needs to not be called 269 * by the driver during suspend/resume, else things will get 270 * a little odd. Check Linux ath9k for more details. 271 */ 272 static int 273 ath_btcoex_aspm_wb195(struct ath_softc *sc) 274 { 275 276 /* XXX TODO: clear device ASPM L0S and L1 */ 277 /* XXX TODO: clear _parent_ ASPM L0S and L1 */ 278 } 279 #endif 280 281 /* 282 * Methods which are required 283 */ 284 285 /* 286 * Attach btcoex to the given interface 287 */ 288 int 289 ath_btcoex_attach(struct ath_softc *sc) 290 { 291 int ret; 292 struct ath_hal *ah = sc->sc_ah; 293 const char *profname; 294 295 /* 296 * No chipset bluetooth coexistence? Then do nothing. 297 */ 298 if (! ath_hal_btcoex_supported(ah)) 299 return (0); 300 301 /* 302 * Look at the hints to determine which bluetooth 303 * profile to configure. 304 */ 305 ret = resource_string_value(device_get_name(sc->sc_dev), 306 device_get_unit(sc->sc_dev), 307 "btcoex_profile", 308 &profname); 309 if (ret != 0) { 310 /* nothing to do */ 311 return (0); 312 } 313 314 if (strncmp(profname, "wb195", 5) == 0) { 315 ret = ath_btcoex_cfg_wb195(sc); 316 } else if (strncmp(profname, "wb222", 5) == 0) { 317 ret = ath_btcoex_cfg_wb222(sc); 318 } else if (strncmp(profname, "wb225", 5) == 0) { 319 ret = ath_btcoex_cfg_wb225(sc); 320 } else { 321 return (0); 322 } 323 324 /* 325 * Propagate up failure from the actual attach phase. 326 */ 327 if (ret != 0) 328 return (ret); 329 330 return (0); 331 } 332 333 /* 334 * Detach btcoex from the given interface 335 */ 336 int 337 ath_btcoex_detach(struct ath_softc *sc) 338 { 339 340 return (0); 341 } 342 343 /* 344 * Configure or disable bluetooth coexistence on the given channel. 345 * 346 * For AR9285/AR9287/AR9485, we'll never see a 5GHz channel, so we just 347 * assume bluetooth coexistence is always on. 348 * 349 * For AR9462, we may see a 5GHz channel; bluetooth coexistence should 350 * not be enabled on those channels. 351 */ 352 int 353 ath_btcoex_enable(struct ath_softc *sc, const struct ieee80211_channel *chan) 354 { 355 356 return (0); 357 } 358 359 /* 360 * Handle ioctl requests from the diagnostic interface. 361 * 362 * The initial part of this code resembles ath_ioctl_diag(); 363 * it's likely a good idea to reduce duplication between 364 * these two routines. 365 */ 366 int 367 ath_btcoex_ioctl(struct ath_softc *sc, struct ath_diag *ad) 368 { 369 unsigned int id = ad->ad_id & ATH_DIAG_ID; 370 void *indata = NULL; 371 void *outdata = NULL; 372 u_int32_t insize = ad->ad_in_size; 373 u_int32_t outsize = ad->ad_out_size; 374 int error = 0; 375 // int val; 376 377 if (ad->ad_id & ATH_DIAG_IN) { 378 /* 379 * Copy in data. 380 */ 381 indata = kmalloc(insize, M_TEMP, M_INTWAIT); 382 if (indata == NULL) { 383 error = ENOMEM; 384 goto bad; 385 } 386 error = copyin(ad->ad_in_data, indata, insize); 387 if (error) 388 goto bad; 389 } 390 if (ad->ad_id & ATH_DIAG_DYN) { 391 /* 392 * Allocate a buffer for the results (otherwise the HAL 393 * returns a pointer to a buffer where we can read the 394 * results). Note that we depend on the HAL leaving this 395 * pointer for us to use below in reclaiming the buffer; 396 * may want to be more defensive. 397 */ 398 outdata = kmalloc(outsize, M_TEMP, M_INTWAIT); 399 if (outdata == NULL) { 400 error = ENOMEM; 401 goto bad; 402 } 403 } 404 switch (id) { 405 default: 406 error = EINVAL; 407 } 408 if (outsize < ad->ad_out_size) 409 ad->ad_out_size = outsize; 410 if (outdata && copyout(outdata, ad->ad_out_data, ad->ad_out_size)) 411 error = EFAULT; 412 bad: 413 if ((ad->ad_id & ATH_DIAG_IN) && indata != NULL) 414 kfree(indata, M_TEMP); 415 if ((ad->ad_id & ATH_DIAG_DYN) && outdata != NULL) 416 kfree(outdata, M_TEMP); 417 return (error); 418 } 419 420