diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/mac.c')
-rw-r--r-- | drivers/net/wireless/ath/ath10k/mac.c | 88 |
1 files changed, 86 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 200752750181..669662a2b416 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -2853,6 +2853,72 @@ static void ath10k_reg_notifier(struct wiphy *wiphy, /* TX handlers */ /***************/ +void ath10k_mac_tx_lock(struct ath10k *ar, int reason) +{ + lockdep_assert_held(&ar->htt.tx_lock); + + WARN_ON(reason >= ATH10K_TX_PAUSE_MAX); + ar->tx_paused |= BIT(reason); + ieee80211_stop_queues(ar->hw); +} + +static void ath10k_mac_tx_unlock_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct ath10k *ar = data; + struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); + + if (arvif->tx_paused) + return; + + ieee80211_wake_queue(ar->hw, arvif->vdev_id); +} + +void ath10k_mac_tx_unlock(struct ath10k *ar, int reason) +{ + lockdep_assert_held(&ar->htt.tx_lock); + + WARN_ON(reason >= ATH10K_TX_PAUSE_MAX); + ar->tx_paused &= ~BIT(reason); + + if (ar->tx_paused) + return; + + ieee80211_iterate_active_interfaces_atomic(ar->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + ath10k_mac_tx_unlock_iter, + ar); +} + +void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason) +{ + struct ath10k *ar = arvif->ar; + + lockdep_assert_held(&ar->htt.tx_lock); + + WARN_ON(reason >= BITS_PER_LONG); + arvif->tx_paused |= BIT(reason); + ieee80211_stop_queue(ar->hw, arvif->vdev_id); +} + +void ath10k_mac_vif_tx_unlock(struct ath10k_vif *arvif, int reason) +{ + struct ath10k *ar = arvif->ar; + + lockdep_assert_held(&ar->htt.tx_lock); + + WARN_ON(reason >= BITS_PER_LONG); + arvif->tx_paused &= ~BIT(reason); + + if (ar->tx_paused) + return; + + if (arvif->tx_paused) + return; + + ieee80211_wake_queue(ar->hw, arvif->vdev_id); +} + static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr) { if (ieee80211_is_mgmt(hdr->frame_control)) @@ -3443,6 +3509,7 @@ void ath10k_halt(struct ath10k *ar) ath10k_monitor_stop(ar); ar->monitor_started = false; + ar->tx_paused = 0; ath10k_scan_finish(ar); ath10k_peer_cleanup_all(ar); @@ -3862,6 +3929,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, int ret = 0; u32 value; int bit; + int i; u32 vdev_param; vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD; @@ -3919,6 +3987,15 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, break; } + /* Using vdev_id as queue number will make it very easy to do per-vif + * tx queue locking. This shouldn't wrap due to interface combinations + * but do a modulo for correctness sake and prevent using offchannel tx + * queues for regular vif tx. + */ + vif->cab_queue = arvif->vdev_id % (IEEE80211_MAX_QUEUES - 1); + for (i = 0; i < ARRAY_SIZE(vif->hw_queue); i++) + vif->hw_queue[i] = arvif->vdev_id % (IEEE80211_MAX_QUEUES - 1); + /* Some firmware revisions don't wait for beacon tx completion before * sending another SWBA event. This could lead to hardware using old * (freed) beacon data in some cases, e.g. tx credit starvation @@ -6547,7 +6624,8 @@ int ath10k_mac_register(struct ath10k *ar) IEEE80211_HW_SW_CRYPTO_CONTROL | IEEE80211_HW_CONNECTION_MONITOR | IEEE80211_HW_WANT_MONITOR_VIF | - IEEE80211_HW_CHANCTX_STA_CSA; + IEEE80211_HW_CHANCTX_STA_CSA | + IEEE80211_HW_QUEUE_CONTROL; ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS; @@ -6603,7 +6681,13 @@ int ath10k_mac_register(struct ath10k *ar) * on LL hardware queues are managed entirely by the FW * so we only advertise to mac we can do the queues thing */ - ar->hw->queues = 4; + ar->hw->queues = IEEE80211_MAX_QUEUES; + + /* vdev_ids are used as hw queue numbers. Make sure offchan tx queue is + * something that vdev_ids can't reach so that we don't stop the queue + * accidentally. + */ + ar->hw->offchannel_tx_hw_queue = IEEE80211_MAX_QUEUES - 1; switch (ar->wmi.op_version) { case ATH10K_FW_WMI_OP_VERSION_MAIN: |