1 /* 2 * Copyright (c) 2008-2011 Atheros Communications Inc. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include "ath9k.h" 18 19 /********************************/ 20 /* LED functions */ 21 /********************************/ 22 23 #ifdef CONFIG_MAC80211_LEDS 24 static void ath_led_brightness(struct led_classdev *led_cdev, 25 enum led_brightness brightness) 26 { 27 struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev); 28 u32 val = (brightness == LED_OFF); 29 30 if (sc->sc_ah->config.led_active_high) 31 val = !val; 32 33 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val); 34 } 35 36 void ath_deinit_leds(struct ath_softc *sc) 37 { 38 if (!sc->led_registered) 39 return; 40 41 ath_led_brightness(&sc->led_cdev, LED_OFF); 42 led_classdev_unregister(&sc->led_cdev); 43 } 44 45 void ath_init_leds(struct ath_softc *sc) 46 { 47 int ret; 48 49 if (AR_SREV_9100(sc->sc_ah)) 50 return; 51 52 if (!ath9k_led_blink) 53 sc->led_cdev.default_trigger = 54 ieee80211_get_radio_led_name(sc->hw); 55 56 snprintf(sc->led_name, sizeof(sc->led_name), 57 "ath9k-%s", wiphy_name(sc->hw->wiphy)); 58 sc->led_cdev.name = sc->led_name; 59 sc->led_cdev.brightness_set = ath_led_brightness; 60 61 ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev); 62 if (ret < 0) 63 return; 64 65 sc->led_registered = true; 66 } 67 68 void ath_fill_led_pin(struct ath_softc *sc) 69 { 70 struct ath_hw *ah = sc->sc_ah; 71 72 if (AR_SREV_9100(ah) || (ah->led_pin >= 0)) 73 return; 74 75 if (AR_SREV_9287(ah)) 76 ah->led_pin = ATH_LED_PIN_9287; 77 else if (AR_SREV_9485(sc->sc_ah)) 78 ah->led_pin = ATH_LED_PIN_9485; 79 else if (AR_SREV_9300(sc->sc_ah)) 80 ah->led_pin = ATH_LED_PIN_9300; 81 else if (AR_SREV_9462(sc->sc_ah) || AR_SREV_9565(sc->sc_ah)) 82 ah->led_pin = ATH_LED_PIN_9462; 83 else 84 ah->led_pin = ATH_LED_PIN_DEF; 85 86 /* Configure gpio 1 for output */ 87 ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); 88 89 /* LED off, active low */ 90 ath9k_hw_set_gpio(ah, ah->led_pin, (ah->config.led_active_high) ? 0 : 1); 91 } 92 #endif 93 94 /*******************/ 95 /* Rfkill */ 96 /*******************/ 97 98 static bool ath_is_rfkill_set(struct ath_softc *sc) 99 { 100 struct ath_hw *ah = sc->sc_ah; 101 bool is_blocked; 102 103 ath9k_ps_wakeup(sc); 104 is_blocked = ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == 105 ah->rfkill_polarity; 106 ath9k_ps_restore(sc); 107 108 return is_blocked; 109 } 110 111 void ath9k_rfkill_poll_state(struct ieee80211_hw *hw) 112 { 113 struct ath_softc *sc = hw->priv; 114 bool blocked = !!ath_is_rfkill_set(sc); 115 116 wiphy_rfkill_set_hw_state(hw->wiphy, blocked); 117 } 118 119 void ath_start_rfkill_poll(struct ath_softc *sc) 120 { 121 struct ath_hw *ah = sc->sc_ah; 122 123 if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) 124 wiphy_rfkill_start_polling(sc->hw->wiphy); 125 } 126 127 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT 128 129 /******************/ 130 /* BTCOEX */ 131 /******************/ 132 133 /* 134 * Detects if there is any priority bt traffic 135 */ 136 static void ath_detect_bt_priority(struct ath_softc *sc) 137 { 138 struct ath_btcoex *btcoex = &sc->btcoex; 139 struct ath_hw *ah = sc->sc_ah; 140 141 if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio)) 142 btcoex->bt_priority_cnt++; 143 144 if (time_after(jiffies, btcoex->bt_priority_time + 145 msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { 146 clear_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags); 147 clear_bit(BT_OP_SCAN, &btcoex->op_flags); 148 /* Detect if colocated bt started scanning */ 149 if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) { 150 ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX, 151 "BT scan detected\n"); 152 set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags); 153 set_bit(BT_OP_SCAN, &btcoex->op_flags); 154 } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { 155 ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX, 156 "BT priority traffic detected\n"); 157 set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags); 158 } 159 160 btcoex->bt_priority_cnt = 0; 161 btcoex->bt_priority_time = jiffies; 162 } 163 } 164 165 static void ath_mci_ftp_adjust(struct ath_softc *sc) 166 { 167 struct ath_btcoex *btcoex = &sc->btcoex; 168 struct ath_mci_profile *mci = &btcoex->mci; 169 struct ath_hw *ah = sc->sc_ah; 170 171 if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) { 172 if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) && 173 (mci->num_pan || mci->num_other_acl)) 174 ah->btcoex_hw.mci.stomp_ftp = 175 (sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH); 176 else 177 ah->btcoex_hw.mci.stomp_ftp = false; 178 btcoex->bt_wait_time = 0; 179 sc->rx.num_pkts = 0; 180 } 181 } 182 183 /* 184 * This is the master bt coex timer which runs for every 185 * 45ms, bt traffic will be given priority during 55% of this 186 * period while wlan gets remaining 45% 187 */ 188 static void ath_btcoex_period_timer(unsigned long data) 189 { 190 struct ath_softc *sc = (struct ath_softc *) data; 191 struct ath_hw *ah = sc->sc_ah; 192 struct ath_btcoex *btcoex = &sc->btcoex; 193 enum ath_stomp_type stomp_type; 194 u32 timer_period; 195 unsigned long flags; 196 197 spin_lock_irqsave(&sc->sc_pm_lock, flags); 198 if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) { 199 btcoex->bt_wait_time += btcoex->btcoex_period; 200 spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 201 goto skip_hw_wakeup; 202 } 203 spin_unlock_irqrestore(&sc->sc_pm_lock, flags); 204 205 ath9k_mci_update_rssi(sc); 206 207 ath9k_ps_wakeup(sc); 208 209 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) 210 ath_detect_bt_priority(sc); 211 212 if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) 213 ath_mci_ftp_adjust(sc); 214 215 spin_lock_bh(&btcoex->btcoex_lock); 216 217 stomp_type = btcoex->bt_stomp_type; 218 timer_period = btcoex->btcoex_no_stomp; 219 220 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) { 221 if (test_bit(BT_OP_SCAN, &btcoex->op_flags)) { 222 stomp_type = ATH_BTCOEX_STOMP_ALL; 223 timer_period = btcoex->btscan_no_stomp; 224 } 225 } else if (btcoex->stomp_audio >= 5) { 226 stomp_type = ATH_BTCOEX_STOMP_AUDIO; 227 btcoex->stomp_audio = 0; 228 } 229 230 ath9k_hw_btcoex_bt_stomp(ah, stomp_type); 231 ath9k_hw_btcoex_enable(ah); 232 233 spin_unlock_bh(&btcoex->btcoex_lock); 234 235 if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) 236 mod_timer(&btcoex->no_stomp_timer, 237 jiffies + msecs_to_jiffies(timer_period)); 238 239 ath9k_ps_restore(sc); 240 241 skip_hw_wakeup: 242 mod_timer(&btcoex->period_timer, 243 jiffies + msecs_to_jiffies(btcoex->btcoex_period)); 244 } 245 246 /* 247 * Generic tsf based hw timer which configures weight 248 * registers to time slice between wlan and bt traffic 249 */ 250 static void ath_btcoex_no_stomp_timer(unsigned long arg) 251 { 252 struct ath_softc *sc = (struct ath_softc *)arg; 253 struct ath_hw *ah = sc->sc_ah; 254 struct ath_btcoex *btcoex = &sc->btcoex; 255 struct ath_common *common = ath9k_hw_common(ah); 256 257 ath_dbg(common, BTCOEX, "no stomp timer running\n"); 258 259 ath9k_ps_wakeup(sc); 260 spin_lock_bh(&btcoex->btcoex_lock); 261 262 if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || 263 (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && 264 test_bit(BT_OP_SCAN, &btcoex->op_flags))) 265 ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); 266 else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) 267 ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); 268 269 ath9k_hw_btcoex_enable(ah); 270 spin_unlock_bh(&btcoex->btcoex_lock); 271 ath9k_ps_restore(sc); 272 } 273 274 static int ath_init_btcoex_timer(struct ath_softc *sc) 275 { 276 struct ath_btcoex *btcoex = &sc->btcoex; 277 278 btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD; 279 btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 280 btcoex->btcoex_period / 100; 281 btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * 282 btcoex->btcoex_period / 100; 283 284 setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, 285 (unsigned long) sc); 286 setup_timer(&btcoex->no_stomp_timer, ath_btcoex_no_stomp_timer, 287 (unsigned long) sc); 288 289 spin_lock_init(&btcoex->btcoex_lock); 290 291 return 0; 292 } 293 294 /* 295 * (Re)start btcoex timers 296 */ 297 void ath9k_btcoex_timer_resume(struct ath_softc *sc) 298 { 299 struct ath_btcoex *btcoex = &sc->btcoex; 300 struct ath_hw *ah = sc->sc_ah; 301 302 ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n"); 303 304 /* make sure duty cycle timer is also stopped when resuming */ 305 del_timer_sync(&btcoex->no_stomp_timer); 306 307 btcoex->bt_priority_cnt = 0; 308 btcoex->bt_priority_time = jiffies; 309 clear_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags); 310 clear_bit(BT_OP_SCAN, &btcoex->op_flags); 311 312 mod_timer(&btcoex->period_timer, jiffies); 313 } 314 315 316 /* 317 * Pause btcoex timer and bt duty cycle timer 318 */ 319 void ath9k_btcoex_timer_pause(struct ath_softc *sc) 320 { 321 struct ath_btcoex *btcoex = &sc->btcoex; 322 323 del_timer_sync(&btcoex->period_timer); 324 del_timer_sync(&btcoex->no_stomp_timer); 325 } 326 327 void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) 328 { 329 struct ath_btcoex *btcoex = &sc->btcoex; 330 331 del_timer_sync(&btcoex->no_stomp_timer); 332 } 333 334 u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) 335 { 336 struct ath_btcoex *btcoex = &sc->btcoex; 337 struct ath_mci_profile *mci = &sc->btcoex.mci; 338 u16 aggr_limit = 0; 339 340 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit) 341 aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4; 342 else if (test_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags)) 343 aggr_limit = min((max_4ms_framelen * 3) / 8, 344 (u32)ATH_AMPDU_LIMIT_MAX); 345 346 return aggr_limit; 347 } 348 349 void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status) 350 { 351 if (status & ATH9K_INT_MCI) 352 ath_mci_intr(sc); 353 } 354 355 void ath9k_start_btcoex(struct ath_softc *sc) 356 { 357 struct ath_hw *ah = sc->sc_ah; 358 359 if ((ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) && 360 !ah->btcoex_hw.enabled) { 361 if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) 362 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT, 363 AR_STOMP_LOW_WLAN_WGHT, 0); 364 else 365 ath9k_hw_btcoex_set_weight(ah, 0, 0, 366 ATH_BTCOEX_STOMP_NONE); 367 ath9k_hw_btcoex_enable(ah); 368 369 if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) 370 ath9k_btcoex_timer_resume(sc); 371 } 372 } 373 374 void ath9k_stop_btcoex(struct ath_softc *sc) 375 { 376 struct ath_hw *ah = sc->sc_ah; 377 378 if (ah->btcoex_hw.enabled && 379 ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { 380 if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) 381 ath9k_btcoex_timer_pause(sc); 382 ath9k_hw_btcoex_disable(ah); 383 if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) 384 ath_mci_flush_profile(&sc->btcoex.mci); 385 } 386 } 387 388 void ath9k_deinit_btcoex(struct ath_softc *sc) 389 { 390 struct ath_hw *ah = sc->sc_ah; 391 392 if (ath9k_hw_mci_is_enabled(ah)) 393 ath_mci_cleanup(sc); 394 } 395 396 int ath9k_init_btcoex(struct ath_softc *sc) 397 { 398 struct ath_txq *txq; 399 struct ath_hw *ah = sc->sc_ah; 400 int r; 401 402 ath9k_hw_btcoex_init_scheme(ah); 403 404 switch (ath9k_hw_get_btcoex_scheme(sc->sc_ah)) { 405 case ATH_BTCOEX_CFG_NONE: 406 break; 407 case ATH_BTCOEX_CFG_2WIRE: 408 ath9k_hw_btcoex_init_2wire(sc->sc_ah); 409 break; 410 case ATH_BTCOEX_CFG_3WIRE: 411 ath9k_hw_btcoex_init_3wire(sc->sc_ah); 412 r = ath_init_btcoex_timer(sc); 413 if (r) 414 return -1; 415 txq = sc->tx.txq_map[IEEE80211_AC_BE]; 416 ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); 417 sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; 418 if (ath9k_hw_mci_is_enabled(ah)) { 419 sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; 420 INIT_LIST_HEAD(&sc->btcoex.mci.info); 421 422 r = ath_mci_setup(sc); 423 if (r) 424 return r; 425 426 ath9k_hw_btcoex_init_mci(ah); 427 } 428 429 break; 430 default: 431 WARN_ON(1); 432 break; 433 } 434 435 return 0; 436 } 437 438 static int ath9k_dump_mci_btcoex(struct ath_softc *sc, u8 *buf, u32 size) 439 { 440 struct ath_btcoex *btcoex = &sc->btcoex; 441 struct ath_mci_profile *mci = &btcoex->mci; 442 struct ath_hw *ah = sc->sc_ah; 443 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw; 444 u32 len = 0; 445 int i; 446 447 ATH_DUMP_BTCOEX("Total BT profiles", NUM_PROF(mci)); 448 ATH_DUMP_BTCOEX("MGMT", mci->num_mgmt); 449 ATH_DUMP_BTCOEX("SCO", mci->num_sco); 450 ATH_DUMP_BTCOEX("A2DP", mci->num_a2dp); 451 ATH_DUMP_BTCOEX("HID", mci->num_hid); 452 ATH_DUMP_BTCOEX("PAN", mci->num_pan); 453 ATH_DUMP_BTCOEX("ACL", mci->num_other_acl); 454 ATH_DUMP_BTCOEX("BDR", mci->num_bdr); 455 ATH_DUMP_BTCOEX("Aggr. Limit", mci->aggr_limit); 456 ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type); 457 ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period); 458 ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle); 459 ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time); 460 ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx); 461 ATH_DUMP_BTCOEX("Concurrent RSSI cnt", btcoex->rssi_count); 462 463 len += scnprintf(buf + len, size - len, "BT Weights: "); 464 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) 465 len += scnprintf(buf + len, size - len, "%08x ", 466 btcoex_hw->bt_weight[i]); 467 len += scnprintf(buf + len, size - len, "\n"); 468 len += scnprintf(buf + len, size - len, "WLAN Weights: "); 469 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++) 470 len += scnprintf(buf + len, size - len, "%08x ", 471 btcoex_hw->wlan_weight[i]); 472 len += scnprintf(buf + len, size - len, "\n"); 473 len += scnprintf(buf + len, size - len, "Tx Priorities: "); 474 for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++) 475 len += scnprintf(buf + len, size - len, "%08x ", 476 btcoex_hw->tx_prio[i]); 477 478 len += scnprintf(buf + len, size - len, "\n"); 479 480 return len; 481 } 482 483 static int ath9k_dump_legacy_btcoex(struct ath_softc *sc, u8 *buf, u32 size) 484 { 485 486 struct ath_btcoex *btcoex = &sc->btcoex; 487 u32 len = 0; 488 489 ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type); 490 ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period); 491 ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle); 492 ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time); 493 494 return len; 495 } 496 497 int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size) 498 { 499 if (ath9k_hw_mci_is_enabled(sc->sc_ah)) 500 return ath9k_dump_mci_btcoex(sc, buf, size); 501 else 502 return ath9k_dump_legacy_btcoex(sc, buf, size); 503 } 504 505 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ 506