0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #include "ath9k.h"
0018
0019
0020
0021
0022
0023 #ifdef CONFIG_MAC80211_LEDS
0024
0025 static void ath_fill_led_pin(struct ath_softc *sc)
0026 {
0027 struct ath_hw *ah = sc->sc_ah;
0028
0029
0030 if (ah->led_pin < 0) {
0031 if (AR_SREV_9287(ah))
0032 ah->led_pin = ATH_LED_PIN_9287;
0033 else if (AR_SREV_9485(ah))
0034 ah->led_pin = ATH_LED_PIN_9485;
0035 else if (AR_SREV_9300(ah))
0036 ah->led_pin = ATH_LED_PIN_9300;
0037 else if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
0038 ah->led_pin = ATH_LED_PIN_9462;
0039 else
0040 ah->led_pin = ATH_LED_PIN_DEF;
0041 }
0042
0043
0044 ath9k_hw_gpio_request_out(ah, ah->led_pin, "ath9k-led",
0045 AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
0046
0047
0048 ath9k_hw_set_gpio(ah, ah->led_pin, ah->config.led_active_high ? 0 : 1);
0049 }
0050
0051 static void ath_led_brightness(struct led_classdev *led_cdev,
0052 enum led_brightness brightness)
0053 {
0054 struct ath_softc *sc = container_of(led_cdev, struct ath_softc, led_cdev);
0055 u32 val = (brightness == LED_OFF);
0056
0057 if (sc->sc_ah->config.led_active_high)
0058 val = !val;
0059
0060 ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, val);
0061 }
0062
0063 void ath_deinit_leds(struct ath_softc *sc)
0064 {
0065 if (!sc->led_registered)
0066 return;
0067
0068 ath_led_brightness(&sc->led_cdev, LED_OFF);
0069 led_classdev_unregister(&sc->led_cdev);
0070
0071 ath9k_hw_gpio_free(sc->sc_ah, sc->sc_ah->led_pin);
0072 }
0073
0074 void ath_init_leds(struct ath_softc *sc)
0075 {
0076 int ret;
0077
0078 if (AR_SREV_9100(sc->sc_ah))
0079 return;
0080
0081 ath_fill_led_pin(sc);
0082
0083 if (!ath9k_led_blink)
0084 sc->led_cdev.default_trigger =
0085 ieee80211_get_radio_led_name(sc->hw);
0086
0087 snprintf(sc->led_name, sizeof(sc->led_name),
0088 "ath9k-%s", wiphy_name(sc->hw->wiphy));
0089 sc->led_cdev.name = sc->led_name;
0090 sc->led_cdev.brightness_set = ath_led_brightness;
0091
0092 ret = led_classdev_register(wiphy_dev(sc->hw->wiphy), &sc->led_cdev);
0093 if (ret < 0)
0094 return;
0095
0096 sc->led_registered = true;
0097 }
0098 #endif
0099
0100
0101
0102
0103
0104 static bool ath_is_rfkill_set(struct ath_softc *sc)
0105 {
0106 struct ath_hw *ah = sc->sc_ah;
0107 bool is_blocked;
0108
0109 ath9k_ps_wakeup(sc);
0110 is_blocked = ath9k_hw_gpio_get(ah, ah->rfkill_gpio) ==
0111 ah->rfkill_polarity;
0112 ath9k_ps_restore(sc);
0113
0114 return is_blocked;
0115 }
0116
0117 void ath9k_rfkill_poll_state(struct ieee80211_hw *hw)
0118 {
0119 struct ath_softc *sc = hw->priv;
0120 bool blocked = !!ath_is_rfkill_set(sc);
0121
0122 wiphy_rfkill_set_hw_state(hw->wiphy, blocked);
0123 }
0124
0125 void ath_start_rfkill_poll(struct ath_softc *sc)
0126 {
0127 struct ath_hw *ah = sc->sc_ah;
0128
0129 if (ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
0130 wiphy_rfkill_start_polling(sc->hw->wiphy);
0131 }
0132
0133 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
0134
0135
0136
0137
0138
0139
0140
0141
0142 static void ath_detect_bt_priority(struct ath_softc *sc)
0143 {
0144 struct ath_btcoex *btcoex = &sc->btcoex;
0145 struct ath_hw *ah = sc->sc_ah;
0146
0147 if (ath9k_hw_gpio_get(sc->sc_ah, ah->btcoex_hw.btpriority_gpio))
0148 btcoex->bt_priority_cnt++;
0149
0150 if (time_after(jiffies, btcoex->bt_priority_time +
0151 msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) {
0152 clear_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
0153 clear_bit(BT_OP_SCAN, &btcoex->op_flags);
0154
0155 if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) {
0156 ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
0157 "BT scan detected\n");
0158 set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
0159 set_bit(BT_OP_SCAN, &btcoex->op_flags);
0160 } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) {
0161 ath_dbg(ath9k_hw_common(sc->sc_ah), BTCOEX,
0162 "BT priority traffic detected\n");
0163 set_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
0164 }
0165
0166 btcoex->bt_priority_cnt = 0;
0167 btcoex->bt_priority_time = jiffies;
0168 }
0169 }
0170
0171 static void ath_mci_ftp_adjust(struct ath_softc *sc)
0172 {
0173 struct ath_btcoex *btcoex = &sc->btcoex;
0174 struct ath_mci_profile *mci = &btcoex->mci;
0175 struct ath_hw *ah = sc->sc_ah;
0176
0177 if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) {
0178 if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) &&
0179 (mci->num_pan || mci->num_other_acl))
0180 ah->btcoex_hw.mci.stomp_ftp =
0181 (sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH);
0182 else
0183 ah->btcoex_hw.mci.stomp_ftp = false;
0184 btcoex->bt_wait_time = 0;
0185 sc->rx.num_pkts = 0;
0186 }
0187 }
0188
0189
0190
0191
0192
0193
0194 static void ath_btcoex_period_timer(struct timer_list *t)
0195 {
0196 struct ath_softc *sc = from_timer(sc, t, btcoex.period_timer);
0197 struct ath_hw *ah = sc->sc_ah;
0198 struct ath_btcoex *btcoex = &sc->btcoex;
0199 enum ath_stomp_type stomp_type;
0200 u32 timer_period;
0201 unsigned long flags;
0202
0203 spin_lock_irqsave(&sc->sc_pm_lock, flags);
0204 if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) {
0205 btcoex->bt_wait_time += btcoex->btcoex_period;
0206 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
0207 goto skip_hw_wakeup;
0208 }
0209 spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
0210
0211 ath9k_ps_wakeup(sc);
0212 spin_lock_bh(&btcoex->btcoex_lock);
0213
0214 if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) {
0215 ath9k_mci_update_rssi(sc);
0216 ath_mci_ftp_adjust(sc);
0217 }
0218
0219 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
0220 ath_detect_bt_priority(sc);
0221
0222 stomp_type = btcoex->bt_stomp_type;
0223 timer_period = btcoex->btcoex_no_stomp;
0224
0225 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) {
0226 if (test_bit(BT_OP_SCAN, &btcoex->op_flags)) {
0227 stomp_type = ATH_BTCOEX_STOMP_ALL;
0228 timer_period = btcoex->btscan_no_stomp;
0229 }
0230 } else if (btcoex->stomp_audio >= 5) {
0231 stomp_type = ATH_BTCOEX_STOMP_AUDIO;
0232 btcoex->stomp_audio = 0;
0233 }
0234
0235 ath9k_hw_btcoex_bt_stomp(ah, stomp_type);
0236 ath9k_hw_btcoex_enable(ah);
0237
0238 spin_unlock_bh(&btcoex->btcoex_lock);
0239
0240 if (btcoex->btcoex_period != btcoex->btcoex_no_stomp)
0241 mod_timer(&btcoex->no_stomp_timer,
0242 jiffies + msecs_to_jiffies(timer_period));
0243
0244 ath9k_ps_restore(sc);
0245
0246 skip_hw_wakeup:
0247 mod_timer(&btcoex->period_timer,
0248 jiffies + msecs_to_jiffies(btcoex->btcoex_period));
0249 }
0250
0251
0252
0253
0254
0255 static void ath_btcoex_no_stomp_timer(struct timer_list *t)
0256 {
0257 struct ath_softc *sc = from_timer(sc, t, btcoex.no_stomp_timer);
0258 struct ath_hw *ah = sc->sc_ah;
0259 struct ath_btcoex *btcoex = &sc->btcoex;
0260
0261 ath9k_ps_wakeup(sc);
0262 spin_lock_bh(&btcoex->btcoex_lock);
0263
0264 if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW ||
0265 (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI) &&
0266 test_bit(BT_OP_SCAN, &btcoex->op_flags)))
0267 ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
0268 else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
0269 ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
0270
0271 ath9k_hw_btcoex_enable(ah);
0272 spin_unlock_bh(&btcoex->btcoex_lock);
0273 ath9k_ps_restore(sc);
0274 }
0275
0276 static void ath_init_btcoex_timer(struct ath_softc *sc)
0277 {
0278 struct ath_btcoex *btcoex = &sc->btcoex;
0279
0280 btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD;
0281 btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) *
0282 btcoex->btcoex_period / 100;
0283 btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) *
0284 btcoex->btcoex_period / 100;
0285 btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
0286
0287 timer_setup(&btcoex->period_timer, ath_btcoex_period_timer, 0);
0288 timer_setup(&btcoex->no_stomp_timer, ath_btcoex_no_stomp_timer, 0);
0289
0290 spin_lock_init(&btcoex->btcoex_lock);
0291 }
0292
0293
0294
0295
0296 void ath9k_btcoex_timer_resume(struct ath_softc *sc)
0297 {
0298 struct ath_btcoex *btcoex = &sc->btcoex;
0299 struct ath_hw *ah = sc->sc_ah;
0300
0301 if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_3WIRE &&
0302 ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI)
0303 return;
0304
0305 ath_dbg(ath9k_hw_common(ah), BTCOEX, "Starting btcoex timers\n");
0306
0307
0308 del_timer_sync(&btcoex->no_stomp_timer);
0309
0310 btcoex->bt_priority_cnt = 0;
0311 btcoex->bt_priority_time = jiffies;
0312 clear_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags);
0313 clear_bit(BT_OP_SCAN, &btcoex->op_flags);
0314
0315 mod_timer(&btcoex->period_timer, jiffies);
0316 }
0317
0318
0319
0320
0321 void ath9k_btcoex_timer_pause(struct ath_softc *sc)
0322 {
0323 struct ath_btcoex *btcoex = &sc->btcoex;
0324 struct ath_hw *ah = sc->sc_ah;
0325
0326 if (ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_3WIRE &&
0327 ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_MCI)
0328 return;
0329
0330 ath_dbg(ath9k_hw_common(ah), BTCOEX, "Stopping btcoex timers\n");
0331
0332 del_timer_sync(&btcoex->period_timer);
0333 del_timer_sync(&btcoex->no_stomp_timer);
0334 }
0335
0336 void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
0337 {
0338 struct ath_btcoex *btcoex = &sc->btcoex;
0339
0340 del_timer_sync(&btcoex->no_stomp_timer);
0341 }
0342
0343 u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen)
0344 {
0345 struct ath_btcoex *btcoex = &sc->btcoex;
0346 struct ath_mci_profile *mci = &sc->btcoex.mci;
0347 u16 aggr_limit = 0;
0348
0349 if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
0350 aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4;
0351 else if (test_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags))
0352 aggr_limit = min((max_4ms_framelen * 3) / 8,
0353 (u32)ATH_AMPDU_LIMIT_MAX);
0354
0355 return aggr_limit;
0356 }
0357
0358 void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status)
0359 {
0360 if (status & ATH9K_INT_MCI)
0361 ath_mci_intr(sc);
0362 }
0363
0364 void ath9k_start_btcoex(struct ath_softc *sc)
0365 {
0366 struct ath_hw *ah = sc->sc_ah;
0367
0368 if (ah->btcoex_hw.enabled ||
0369 ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
0370 return;
0371
0372 if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
0373 ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
0374 AR_STOMP_LOW_WLAN_WGHT, 0);
0375 else
0376 ath9k_hw_btcoex_set_weight(ah, 0, 0,
0377 ATH_BTCOEX_STOMP_NONE);
0378 ath9k_hw_btcoex_enable(ah);
0379 ath9k_btcoex_timer_resume(sc);
0380 }
0381
0382 void ath9k_stop_btcoex(struct ath_softc *sc)
0383 {
0384 struct ath_hw *ah = sc->sc_ah;
0385
0386 if (!ah->btcoex_hw.enabled ||
0387 ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_NONE)
0388 return;
0389
0390 ath9k_btcoex_timer_pause(sc);
0391 ath9k_hw_btcoex_disable(ah);
0392
0393 if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI)
0394 ath_mci_flush_profile(&sc->btcoex.mci);
0395 }
0396
0397 void ath9k_deinit_btcoex(struct ath_softc *sc)
0398 {
0399 struct ath_hw *ah = sc->sc_ah;
0400
0401 if (ath9k_hw_mci_is_enabled(ah))
0402 ath_mci_cleanup(sc);
0403 else {
0404 enum ath_btcoex_scheme scheme = ath9k_hw_get_btcoex_scheme(ah);
0405
0406 if (scheme == ATH_BTCOEX_CFG_2WIRE ||
0407 scheme == ATH_BTCOEX_CFG_3WIRE)
0408 ath9k_hw_btcoex_deinit(sc->sc_ah);
0409 }
0410 }
0411
0412 int ath9k_init_btcoex(struct ath_softc *sc)
0413 {
0414 struct ath_txq *txq;
0415 struct ath_hw *ah = sc->sc_ah;
0416 int r;
0417
0418 ath9k_hw_btcoex_init_scheme(ah);
0419
0420 switch (ath9k_hw_get_btcoex_scheme(sc->sc_ah)) {
0421 case ATH_BTCOEX_CFG_NONE:
0422 break;
0423 case ATH_BTCOEX_CFG_2WIRE:
0424 ath9k_hw_btcoex_init_2wire(sc->sc_ah);
0425 break;
0426 case ATH_BTCOEX_CFG_3WIRE:
0427 ath9k_hw_btcoex_init_3wire(sc->sc_ah);
0428 ath_init_btcoex_timer(sc);
0429 txq = sc->tx.txq_map[IEEE80211_AC_BE];
0430 ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
0431 break;
0432 case ATH_BTCOEX_CFG_MCI:
0433 ath_init_btcoex_timer(sc);
0434
0435 sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
0436 INIT_LIST_HEAD(&sc->btcoex.mci.info);
0437 ath9k_hw_btcoex_init_mci(ah);
0438
0439 r = ath_mci_setup(sc);
0440 if (r)
0441 return r;
0442
0443 break;
0444 default:
0445 WARN_ON(1);
0446 break;
0447 }
0448
0449 return 0;
0450 }
0451
0452 static int ath9k_dump_mci_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
0453 {
0454 struct ath_btcoex *btcoex = &sc->btcoex;
0455 struct ath_mci_profile *mci = &btcoex->mci;
0456 struct ath_hw *ah = sc->sc_ah;
0457 struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
0458 u32 len = 0;
0459 int i;
0460
0461 ATH_DUMP_BTCOEX("Total BT profiles", NUM_PROF(mci));
0462 ATH_DUMP_BTCOEX("MGMT", mci->num_mgmt);
0463 ATH_DUMP_BTCOEX("SCO", mci->num_sco);
0464 ATH_DUMP_BTCOEX("A2DP", mci->num_a2dp);
0465 ATH_DUMP_BTCOEX("HID", mci->num_hid);
0466 ATH_DUMP_BTCOEX("PAN", mci->num_pan);
0467 ATH_DUMP_BTCOEX("ACL", mci->num_other_acl);
0468 ATH_DUMP_BTCOEX("BDR", mci->num_bdr);
0469 ATH_DUMP_BTCOEX("Aggr. Limit", mci->aggr_limit);
0470 ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type);
0471 ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period);
0472 ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle);
0473 ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time);
0474 ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx);
0475 ATH_DUMP_BTCOEX("Concurrent RSSI cnt", btcoex->rssi_count);
0476
0477 len += scnprintf(buf + len, size - len, "BT Weights: ");
0478 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
0479 len += scnprintf(buf + len, size - len, "%08x ",
0480 btcoex_hw->bt_weight[i]);
0481 len += scnprintf(buf + len, size - len, "\n");
0482 len += scnprintf(buf + len, size - len, "WLAN Weights: ");
0483 for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
0484 len += scnprintf(buf + len, size - len, "%08x ",
0485 btcoex_hw->wlan_weight[i]);
0486 len += scnprintf(buf + len, size - len, "\n");
0487 len += scnprintf(buf + len, size - len, "Tx Priorities: ");
0488 for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++)
0489 len += scnprintf(buf + len, size - len, "%08x ",
0490 btcoex_hw->tx_prio[i]);
0491
0492 len += scnprintf(buf + len, size - len, "\n");
0493
0494 return len;
0495 }
0496
0497 static int ath9k_dump_legacy_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
0498 {
0499
0500 struct ath_btcoex *btcoex = &sc->btcoex;
0501 u32 len = 0;
0502
0503 ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type);
0504 ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period);
0505 ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle);
0506 ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time);
0507
0508 return len;
0509 }
0510
0511 int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
0512 {
0513 if (ath9k_hw_mci_is_enabled(sc->sc_ah))
0514 return ath9k_dump_mci_btcoex(sc, buf, size);
0515 else
0516 return ath9k_dump_legacy_btcoex(sc, buf, size);
0517 }
0518
0519 #endif