static int ath9k_rng_data_read(struct ath_softc *sc, u32 *buf, u32 buf_size) { int i, j; u32 v1, v2, rng_last = sc->rng_last; struct ath_hw *ah = sc->sc_ah; ath9k_ps_wakeup(sc); REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 1); REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5); REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0); for (i = 0, j = 0; i < buf_size; i++) { v1 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; v2 = REG_READ(ah, AR_PHY_TST_ADC) & 0xffff; /* wait for data ready */ if (v1 && v2 && rng_last != v1 && v1 != v2 && v1 != 0xffff && v2 != 0xffff) buf[j++] = (v1 << 16) | v2; rng_last = v2; } ath9k_ps_restore(sc); sc->rng_last = rng_last; return j << 2; }
/* * This is the master bt coex timer which runs for every * 45ms, bt traffic will be given priority during 55% of this * period while wlan gets remaining 45% */ static void ath_btcoex_period_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *) data; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; u32 timer_period; bool is_btscan; ath9k_ps_wakeup(sc); ath_detect_bt_priority(sc); is_btscan = sc->sc_flags & SC_OP_BT_SCAN; spin_lock_bh(&btcoex->btcoex_lock); ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type); spin_unlock_bh(&btcoex->btcoex_lock); if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { if (btcoex->hw_timer_enabled) ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); timer_period = is_btscan ? btcoex->btscan_no_stomp : btcoex->btcoex_no_stomp; ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period, timer_period * 10); btcoex->hw_timer_enabled = true; } ath9k_ps_restore(sc); mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD)); }
void ath_hw_pll_work(struct work_struct *work) { u32 pll_sqsum; struct ath_softc *sc = container_of(work, struct ath_softc, hw_pll_work.work); /* * ensure that the PLL WAR is executed only * after the STA is associated (or) if the * beaconing had started in interfaces that * uses beacons. */ if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) return; if (sc->tx99_state) return; ath9k_ps_wakeup(sc); pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); ath9k_ps_restore(sc); if (ath_hw_pll_rx_hang_check(sc, pll_sqsum)) return; ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); }
void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; struct ieee80211_channel *channel = hw->conf.channel; int r; ath9k_ps_wakeup(sc); cancel_delayed_work_sync(&sc->hw_pll_work); spin_lock_bh(&sc->sc_pcu_lock); ieee80211_stop_queues(hw); /* * Keep the LED on when the radio is disabled * during idle unassociated state. */ if (!sc->ps_idle) { ath9k_hw_set_gpio(ah, ah->led_pin, 1); ath9k_hw_cfg_gpio_input(ah, ah->led_pin); } /* Disable interrupts */ ath9k_hw_disable_interrupts(ah); ath_drain_all_txq(sc, false); /* clear pendin
void ath_hw_check(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); struct ath_common *common = ath9k_hw_common(sc->sc_ah); unsigned long flags; int busy; ath9k_ps_wakeup(sc); if (ath9k_hw_check_alive(sc->sc_ah)) goto out; spin_lock_irqsave(&common->cc_lock, flags); busy = ath_update_survey_stats(sc); spin_unlock_irqrestore(&common->cc_lock, flags); ath_dbg(common, ATH_DBG_RESET, "Possible baseband hang, " "busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); if (busy >= 99) { if (++sc->hw_busy_count >= 3) { spin_lock_bh(&sc->sc_pcu_lock); ath_reset(sc, true); spin_unlock_bh(&sc->sc_pcu_lock); } } else if (busy >= 0) sc->hw_busy_count = 0; out: ath9k_ps_restore(sc); }
void ath9k_deinit_device(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; int i = 0; ath9k_ps_wakeup(sc); wiphy_rfkill_stop_polling(sc->hw->wiphy); ath_deinit_leds(sc); for (i = 0; i < sc->num_sec_wiphy; i++) { struct ath_wiphy *aphy = sc->sec_wiphy[i]; if (aphy == NULL) continue; sc->sec_wiphy[i] = NULL; ieee80211_unregister_hw(aphy->hw); ieee80211_free_hw(aphy->hw); } kfree(sc->sec_wiphy); ieee80211_unregister_hw(hw); ath_rx_cleanup(sc); ath_tx_cleanup(sc); ath9k_deinit_softc(sc); }
static ssize_t write_file_bt_ant_diversity(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath9k_hw_capabilities *pCap = &sc->sc_ah->caps; unsigned long bt_ant_diversity; char buf[32]; ssize_t len; len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) return -EFAULT; if (!(pCap->hw_caps & ATH9K_HW_CAP_BT_ANT_DIV)) goto exit; buf[len] = '\0'; if (kstrtoul(buf, 0, &bt_ant_diversity)) return -EINVAL; common->bt_ant_diversity = !!bt_ant_diversity; ath9k_ps_wakeup(sc); ath9k_hw_set_bt_ant_diversity(sc->sc_ah, common->bt_ant_diversity); ath_dbg(common, CONFIG, "Enable WLAN/BT RX Antenna diversity: %d\n", common->bt_ant_diversity); ath9k_ps_restore(sc); exit: return count; }
static int open_file_regdump(struct inode *inode, struct file *file) { struct ath_softc *sc = inode->i_private; unsigned int len = 0; u8 *buf; int i; unsigned long num_regs, regdump_len, max_reg_offset; max_reg_offset = AR_SREV_9300_20_OR_LATER(sc->sc_ah) ? 0x16bd4 : 0xb500; num_regs = max_reg_offset / 4 + 1; regdump_len = num_regs * REGDUMP_LINE_SIZE + 1; buf = vmalloc(regdump_len); if (!buf) return -ENOMEM; ath9k_ps_wakeup(sc); for (i = 0; i < num_regs; i++) len += scnprintf(buf + len, regdump_len - len, "0x%06x 0x%08x\n", i << 2, REG_READ(sc->sc_ah, i << 2)); ath9k_ps_restore(sc); file->private_data = buf; return 0; }
static int ath_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; u32 val; /* * Suspend/Resume resets the PCI configuration space, so we have to * re-disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ pci_read_config_dword(pdev, 0x40, &val); if ((val & 0x0000ff00) != 0) pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); ath9k_ps_wakeup(sc); /* Enable LED */ ath9k_hw_cfg_output(sc->sc_ah, sc->sc_ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(sc->sc_ah, sc->sc_ah->led_pin, 0); /* * Reset key cache to sane defaults (all entries cleared) instead of * semi-random values after suspend/resume. */ ath9k_cmn_init_crypto(sc->sc_ah); ath9k_ps_restore(sc); sc->ps_idle = true; ath_radio_disable(sc, hw); return 0; }
static void ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_regulatory *reg = ath9k_hw_regulatory(ah); ath_reg_notifier_apply(wiphy, request, reg); /* synchronize DFS detector if regulatory domain changed */ if (sc->dfs_detector != NULL) sc->dfs_detector->set_dfs_domain(sc->dfs_detector, request->dfs_region); /* Set tx power */ if (!ah->curchan) return; sc->cur_chan->txpower = 2 * ah->curchan->chan->max_power; ath9k_ps_wakeup(sc); ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false); ath9k_cmn_update_txpow(ah, sc->cur_chan->cur_txpower, sc->cur_chan->txpower, &sc->cur_chan->cur_txpower); ath9k_ps_restore(sc); }
static void ath9k_tx99_deinit(struct ath_softc *sc) { ath_reset(sc, NULL); ath9k_ps_wakeup(sc); ath9k_tx99_stop(sc); ath9k_ps_restore(sc); }
/* * This is the master bt coex timer which runs for every * 45ms, bt traffic will be given priority during 55% of this * period while wlan gets remaining 45% */ static void ath_btcoex_period_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *) data; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; u32 timer_period; bool is_btscan; unsigned long flags; spin_lock_irqsave(&sc->sc_pm_lock, flags); if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) { spin_unlock_irqrestore(&sc->sc_pm_lock, flags); goto skip_hw_wakeup; } spin_unlock_irqrestore(&sc->sc_pm_lock, flags); ath9k_ps_wakeup(sc); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) ath_detect_bt_priority(sc); is_btscan = test_bit(BT_OP_SCAN, &btcoex->op_flags); btcoex->bt_wait_time += btcoex->btcoex_period; if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) { if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) && (mci->num_pan || mci->num_other_acl)) ah->btcoex_hw.mci.stomp_ftp = (sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH); else ah->btcoex_hw.mci.stomp_ftp = false; btcoex->bt_wait_time = 0; sc->rx.num_pkts = 0; } spin_lock_bh(&btcoex->btcoex_lock); ath9k_hw_btcoex_bt_stomp(ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type); ath9k_hw_btcoex_enable(ah); spin_unlock_bh(&btcoex->btcoex_lock); if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) { if (btcoex->hw_timer_enabled) ath9k_gen_timer_stop(ah, btcoex->no_stomp_timer); timer_period = is_btscan ? btcoex->btscan_no_stomp : btcoex->btcoex_no_stomp; ath9k_gen_timer_start(ah, btcoex->no_stomp_timer, timer_period, timer_period * 10); btcoex->hw_timer_enabled = true; } ath9k_ps_restore(sc); skip_hw_wakeup: timer_period = btcoex->btcoex_period; mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period)); }
/* * This is the master bt coex timer which runs for every * 45ms, bt traffic will be given priority during 55% of this * period while wlan gets remaining 45% */ static void ath_btcoex_period_timer(unsigned long data) { struct ath_softc *sc = (struct ath_softc *) data; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; enum ath_stomp_type stomp_type; u32 timer_period; unsigned long flags; spin_lock_irqsave(&sc->sc_pm_lock, flags); if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) { btcoex->bt_wait_time += btcoex->btcoex_period; spin_unlock_irqrestore(&sc->sc_pm_lock, flags); goto skip_hw_wakeup; } spin_unlock_irqrestore(&sc->sc_pm_lock, flags); ath9k_mci_update_rssi(sc); ath9k_ps_wakeup(sc); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) ath_detect_bt_priority(sc); if (ah->caps.hw_caps & ATH9K_HW_CAP_MCI) ath_mci_ftp_adjust(sc); spin_lock_bh(&btcoex->btcoex_lock); stomp_type = btcoex->bt_stomp_type; timer_period = btcoex->btcoex_no_stomp; if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) { if (test_bit(BT_OP_SCAN, &btcoex->op_flags)) { stomp_type = ATH_BTCOEX_STOMP_ALL; timer_period = btcoex->btscan_no_stomp; } } else if (btcoex->stomp_audio >= 5) { stomp_type = ATH_BTCOEX_STOMP_AUDIO; btcoex->stomp_audio = 0; } ath9k_hw_btcoex_bt_stomp(ah, stomp_type); ath9k_hw_btcoex_enable(ah); spin_unlock_bh(&btcoex->btcoex_lock); if (btcoex->btcoex_period != btcoex->btcoex_no_stomp) mod_timer(&btcoex->no_stomp_timer, jiffies + msecs_to_jiffies(timer_period)); ath9k_ps_restore(sc); skip_hw_wakeup: mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(btcoex->btcoex_period)); }
static bool ath_is_rfkill_set(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; bool is_blocked; ath9k_ps_wakeup(sc); is_blocked = ath9k_btcoex_ath9k_hw_gpio_get(ah, ah->rfkill_gpio) == ah->rfkill_polarity; ath9k_ps_restore(sc); return is_blocked; }
static int ath9k_tx99_init(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_tx_control txctl; int r; if (test_bit(ATH_OP_INVALID, &common->op_flags)) { ath_err(common, "driver is in invalid state unable to use TX99"); return -EINVAL; } sc->tx99_skb = ath9k_build_tx99_skb(sc); if (!sc->tx99_skb) return -ENOMEM; memset(&txctl, 0, sizeof(txctl)); txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; ath_reset(sc, NULL); ath9k_ps_wakeup(sc); ath9k_hw_disable_interrupts(ah); atomic_set(&ah->intr_ref_cnt, -1); ath_drain_all_txq(sc); ath_stoprecv(sc); sc->tx99_state = true; ieee80211_stop_queues(hw); if (sc->tx99_power == MAX_RATE_POWER + 1) sc->tx99_power = MAX_RATE_POWER; ath9k_hw_tx99_set_txpower(ah, sc->tx99_power); r = ath9k_tx99_send(sc, sc->tx99_skb, &txctl); if (r) { ath_dbg(common, XMIT, "Failed to xmit TX99 skb\n"); return r; } ath_dbg(common, XMIT, "TX99 xmit started using %d ( %ddBm)\n", sc->tx99_power, sc->tx99_power / 2); /* We leave the harware awake as it will be chugging on */ return 0; }
static ssize_t read_file_regval(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_hw *ah = sc->sc_ah; char buf[32]; unsigned int len; u32 regval; ath9k_ps_wakeup(sc); regval = REG_READ_D(ah, sc->debug.regidx); ath9k_ps_restore(sc); len = sprintf(buf, "0x%08x\n", regval); return simple_read_from_buffer(user_buf, count, ppos, buf, len); }
void ath9k_deinit_device(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; ath9k_ps_wakeup(sc); wiphy_rfkill_stop_polling(sc->hw->wiphy); ath_deinit_leds(sc); ath9k_ps_restore(sc); ieee80211_unregister_hw(hw); ath_rx_cleanup(sc); ath_tx_cleanup(sc); ath9k_deinit_softc(sc); }
static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *channel = hw->conf.channel; int r; ath9k_ps_wakeup(sc); spin_lock_bh(&sc->sc_pcu_lock); ath9k_hw_configpcipowersave(ah, 0, 0); if (!ah->curchan) ah->curchan = ath9k_cmn_get_curchannel(sc->hw, ah); r = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); if (r) { ath_err(common, "Unable to reset channel (%u MHz), reset status %d\n", channel->center_freq, r); } ath9k_cmn_update_txpow(ah, sc->curtxpow, sc->config.txpowlimit, &sc->curtxpow); if (ath_startrecv(sc) != 0) { ath_err(common, "Unable to restart recv logic\n"); goto out; } if (sc->sc_flags & SC_OP_BEACONS) ath_set_beacon(sc); /* restart beacons */ /* Re-Enable interrupts */ ath9k_hw_set_interrupts(ah, ah->imask); /* Enable LED */ ath9k_hw_cfg_output(ah, ah->led_pin, AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(ah, ah->led_pin, 0); ieee80211_wake_queues(hw); ieee80211_queue_delayed_work(hw, &sc->hw_pll_work, HZ/2); out: spin_unlock_bh(&sc->sc_pcu_lock); ath9k_ps_restore(sc); }
void ath_hw_pll_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, hw_pll_work.work); u32 pll_sqsum; if (AR_SREV_9485(sc->sc_ah)) { ath9k_ps_wakeup(sc); pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); ath9k_ps_restore(sc); ath_hw_pll_rx_hang_check(sc, pll_sqsum); ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/5); } }
/* * Checks if the BB/MAC is hung. */ void ath_hw_check(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); struct ath_common *common = ath9k_hw_common(sc->sc_ah); unsigned long flags; int busy; u8 is_alive, nbeacon = 1; enum ath_reset_type type; ath9k_ps_wakeup(sc); is_alive = ath9k_hw_check_alive(sc->sc_ah); if (is_alive && !AR_SREV_9300(sc->sc_ah)) goto out; else if (!is_alive && AR_SREV_9300(sc->sc_ah)) { ath_dbg(common, RESET, "DCU stuck is detected. Schedule chip reset\n"); type = RESET_TYPE_MAC_HANG; goto sched_reset; } spin_lock_irqsave(&common->cc_lock, flags); busy = ath_update_survey_stats(sc); spin_unlock_irqrestore(&common->cc_lock, flags); ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n", busy, sc->hw_busy_count + 1); if (busy >= 99) { if (++sc->hw_busy_count >= 3) { type = RESET_TYPE_BB_HANG; goto sched_reset; } } else if (busy >= 0) { sc->hw_busy_count = 0; nbeacon = 3; } ath_start_rx_poll(sc, nbeacon); goto out; sched_reset: ath9k_queue_reset(sc, type); out: ath9k_ps_restore(sc); }
/* * Generic tsf based hw timer which configures weight * registers to time slice between wlan and bt traffic */ static void ath_btcoex_no_stomp_timer(unsigned long arg) { struct ath_softc *sc = (struct ath_softc *)arg; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; ath9k_ps_wakeup(sc); spin_lock_bh(&btcoex->btcoex_lock); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && test_bit(BT_OP_SCAN, &btcoex->op_flags))) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); ath9k_hw_btcoex_enable(ah); spin_unlock_bh(&btcoex->btcoex_lock); ath9k_ps_restore(sc); }
/* * Checks if the BB/MAC is hung. */ bool ath_hw_check(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); enum ath_reset_type type; bool is_alive; ath9k_ps_wakeup(sc); is_alive = ath9k_hw_check_alive(sc->sc_ah); if (!is_alive) { ath_dbg(common, RESET, "HW hang detected, schedule chip reset\n"); type = RESET_TYPE_MAC_HANG; ath9k_queue_reset(sc, type); } ath9k_ps_restore(sc); return is_alive; }
/* * PA Pre-distortion. */ static void ath_paprd_activate(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath9k_hw_cal_data *caldata = ah->caldata; int chain; if (!caldata || !caldata->paprd_done) return; ath9k_ps_wakeup(sc); ar9003_paprd_enable(ah, false); for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { if (!(ah->txchainmask & BIT(chain))) continue; ar9003_paprd_populate_single_table(ah, caldata, chain); } ar9003_paprd_enable(ah, true); ath9k_ps_restore(sc); }
/* * Generic tsf based hw timer which configures weight * registers to time slice between wlan and bt traffic */ static void ath_btcoex_no_stomp_timer(void *arg) { struct ath_softc *sc = (struct ath_softc *)arg; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; struct ath_common *common = ath9k_hw_common(ah); bool is_btscan = sc->sc_flags & SC_OP_BT_SCAN; ath_dbg(common, ATH_DBG_BTCOEX, "no stomp timer running\n"); ath9k_ps_wakeup(sc); spin_lock_bh(&btcoex->btcoex_lock); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); spin_unlock_bh(&btcoex->btcoex_lock); ath9k_ps_restore(sc); }
/* * Generic tsf based hw timer which configures weight * registers to time slice between wlan and bt traffic */ static void ath_btcoex_no_stomp_timer(void *arg) { struct ath_softc *sc = (struct ath_softc *)arg; struct ath_hw *ah = sc->sc_ah; struct ath_btcoex *btcoex = &sc->btcoex; struct ath_common *common = ath9k_hw_common(ah); ath_dbg(common, BTCOEX, "no stomp timer running\n"); ath9k_ps_wakeup(sc); spin_lock_bh(&btcoex->btcoex_lock); if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || test_bit(BT_OP_SCAN, &btcoex->op_flags)) ath9k_btcoex_ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath9k_btcoex_ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); ath9k_btcoex_ath9k_hw_btcoex_enable(ah); spin_unlock_bh(&btcoex->btcoex_lock); ath9k_ps_restore(sc); }
static int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_regulatory *reg = ath9k_hw_regulatory(ah); int ret; ret = ath_reg_notifier_apply(wiphy, request, reg); /* Set tx power */ if (ah->curchan) { sc->config.txpowlimit = 2 * ah->curchan->chan->max_power; ath9k_ps_wakeup(sc); ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false); sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; ath9k_ps_restore(sc); } return ret; }
static ssize_t write_file_regval(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; struct ath_hw *ah = sc->sc_ah; unsigned long regval; char buf[32]; ssize_t len; len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) return -EFAULT; buf[len] = '\0'; if (kstrtoul(buf, 0, ®val)) return -EINVAL; ath9k_ps_wakeup(sc); REG_WRITE_D(ah, sc->debug.regidx, regval); ath9k_ps_restore(sc); return count; }
static ssize_t write_file_tx99_power(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct ath_softc *sc = file->private_data; int r; u8 tx_power; r = kstrtou8_from_user(user_buf, count, 0, &tx_power); if (r) return r; if (tx_power > MAX_RATE_POWER) return -EINVAL; sc->tx99_power = tx_power; ath9k_ps_wakeup(sc); ath9k_hw_tx99_set_txpower(sc->sc_ah, sc->tx99_power); ath9k_ps_restore(sc); return count; }
static int open_file_regdump(struct inode *inode, struct file *file) { struct ath_softc *sc = inode->i_private; unsigned int len = 0; u8 *buf; int i, j = 0; unsigned long num_regs, regdump_len, max_reg_offset; const struct reg_hole { u32 start; u32 end; } reg_hole_list[] = { {0x0200, 0x07fc}, {0x0c00, 0x0ffc}, {0x2000, 0x3ffc}, {0x4100, 0x6ffc}, {0x705c, 0x7ffc}, {0x0000, 0x0000} }; max_reg_offset = AR_SREV_9300_20_OR_LATER(sc->sc_ah) ? 0x8800 : 0xb500; num_regs = max_reg_offset / 4 + 1; regdump_len = num_regs * REGDUMP_LINE_SIZE + 1; buf = vmalloc(regdump_len); if (!buf) return -ENOMEM; ath9k_ps_wakeup(sc); for (i = 0; i < num_regs; i++) { if (reg_hole_list[j].start == i << 2) { i = reg_hole_list[j].end >> 2; j++; continue; } len += scnprintf(buf + len, regdump_len - len, "0x%06x 0x%08x\n", i << 2, REG_READ(sc->sc_ah, i << 2)); }
void ath9k_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); u32 status = sc->intrstatus; u32 rxmask; if ((status & ATH9K_INT_FATAL) || (status & ATH9K_INT_BB_WATCHDOG)) { spin_lock(&sc->sc_pcu_lock); ath_reset(sc, true); spin_unlock(&sc->sc_pcu_lock); return; } ath9k_ps_wakeup(sc); spin_lock(&sc->sc_pcu_lock); /* * Only run the baseband hang check if beacons stop working in AP or * IBSS mode, because it has a high false positive rate. For station * mode it should not be necessary, since the upper layers will detect * this through a beacon miss automatically and the following channel * change will trigger a hardware reset anyway */ if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0 && !ath9k_hw_check_alive(ah)) ieee80211_queue_work(sc->hw, &sc->hw_check_work); if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { /* * TSF sync does not look correct; remain awake to sync with * the next Beacon. */ ath_dbg(common, ATH_DBG_PS, "TSFOOR - Sync with next Beacon\n"); sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC | PS_TSFOOR_SYNC; } if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); else rxmask = (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN); if (status & rxmask) { /* Check for high priority Rx first */ if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && (status & ATH9K_INT_RXHP)) ath_rx_tasklet(sc, 0, true); ath_rx_tasklet(sc, 0, false); } if (status & ATH9K_INT_TX) { if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ath_tx_edma_tasklet(sc); else ath_tx_tasklet(sc); } if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE) if (status & ATH9K_INT_GENTIMER) ath_gen_timer_isr(sc->sc_ah); /* re-enable hardware interrupt */ ath9k_hw_enable_interrupts(ah); spin_unlock(&sc->sc_pcu_lock); ath9k_ps_restore(sc); }