void ath10k_htt_tx_txq_recalc(struct ieee80211_hw *hw,
struct ieee80211_txq *txq);
void ath10k_htt_tx_txq_sync(struct ath10k *ar);
-void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt,
- bool is_mgmt);
-int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt,
- bool is_mgmt,
- bool is_presp);
+void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt);
+int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt);
+void ath10k_htt_tx_mgmt_dec_pending(struct ath10k_htt *htt);
+int ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt,
+ bool is_presp);
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb);
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
break;
}
- ath10k_txrx_tx_unref(htt, &tx_done);
+ status = ath10k_txrx_tx_unref(htt, &tx_done);
+ if (!status) {
+ spin_lock_bh(&htt->tx_lock);
+ ath10k_htt_tx_mgmt_dec_pending(htt);
+ spin_unlock_bh(&htt->tx_lock);
+ }
ath10k_mac_tx_push_pending(ar);
break;
}
spin_unlock_bh(&ar->htt.tx_lock);
}
-void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt,
- bool is_mgmt)
+void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
{
lockdep_assert_held(&htt->tx_lock);
- if (is_mgmt)
- htt->num_pending_mgmt_tx--;
-
htt->num_pending_tx--;
if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
}
-int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt,
- bool is_mgmt,
- bool is_presp)
+int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
{
- struct ath10k *ar = htt->ar;
-
lockdep_assert_held(&htt->tx_lock);
if (htt->num_pending_tx >= htt->max_num_pending_tx)
return -EBUSY;
- if (is_mgmt &&
- is_presp &&
- ar->hw_params.max_probe_resp_desc_thres &&
- ar->hw_params.max_probe_resp_desc_thres < htt->num_pending_mgmt_tx)
- return -EBUSY;
-
- if (is_mgmt)
- htt->num_pending_mgmt_tx++;
-
htt->num_pending_tx++;
if (htt->num_pending_tx == htt->max_num_pending_tx)
ath10k_mac_tx_lock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
return 0;
}
+int ath10k_htt_tx_mgmt_inc_pending(struct ath10k_htt *htt, bool is_mgmt,
+ bool is_presp)
+{
+ struct ath10k *ar = htt->ar;
+
+ lockdep_assert_held(&htt->tx_lock);
+
+ if (!is_mgmt || !ar->hw_params.max_probe_resp_desc_thres)
+ return 0;
+
+ if (is_presp &&
+ ar->hw_params.max_probe_resp_desc_thres < htt->num_pending_mgmt_tx)
+ return -EBUSY;
+
+ htt->num_pending_mgmt_tx++;
+
+ return 0;
+}
+
+void ath10k_htt_tx_mgmt_dec_pending(struct ath10k_htt *htt)
+{
+ lockdep_assert_held(&htt->tx_lock);
+
+ if (!htt->ar->hw_params.max_probe_resp_desc_thres)
+ return;
+
+ htt->num_pending_mgmt_tx--;
+}
+
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb)
{
struct ath10k *ar = htt->ar;
int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
struct ieee80211_txq *txq)
{
- const bool is_mgmt = false;
- const bool is_presp = false;
struct ath10k *ar = hw->priv;
struct ath10k_htt *htt = &ar->htt;
struct ath10k_txq *artxq = (void *)txq->drv_priv;
int ret;
spin_lock_bh(&ar->htt.tx_lock);
- ret = ath10k_htt_tx_inc_pending(htt, is_mgmt, is_presp);
+ ret = ath10k_htt_tx_inc_pending(htt);
spin_unlock_bh(&ar->htt.tx_lock);
if (ret)
skb = ieee80211_tx_dequeue(hw, txq);
if (!skb) {
spin_lock_bh(&ar->htt.tx_lock);
- ath10k_htt_tx_dec_pending(htt, is_mgmt);
+ ath10k_htt_tx_dec_pending(htt);
spin_unlock_bh(&ar->htt.tx_lock);
return -ENOENT;
ath10k_warn(ar, "failed to push frame: %d\n", ret);
spin_lock_bh(&ar->htt.tx_lock);
- ath10k_htt_tx_dec_pending(htt, is_mgmt);
+ ath10k_htt_tx_dec_pending(htt);
spin_unlock_bh(&ar->htt.tx_lock);
return ret;
txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
is_htt = (txpath == ATH10K_MAC_TX_HTT ||
txpath == ATH10K_MAC_TX_HTT_MGMT);
+ is_mgmt = (txpath == ATH10K_MAC_TX_HTT_MGMT);
if (is_htt) {
spin_lock_bh(&ar->htt.tx_lock);
-
- is_mgmt = ieee80211_is_mgmt(hdr->frame_control);
is_presp = ieee80211_is_probe_resp(hdr->frame_control);
- ret = ath10k_htt_tx_inc_pending(htt, is_mgmt, is_presp);
+ ret = ath10k_htt_tx_inc_pending(htt);
if (ret) {
ath10k_warn(ar, "failed to increase tx pending count: %d, dropping\n",
ret);
return;
}
+ ret = ath10k_htt_tx_mgmt_inc_pending(htt, is_mgmt, is_presp);
+ if (ret) {
+ ath10k_warn(ar, "failed to increase tx mgmt pending count: %d, dropping\n",
+ ret);
+ ath10k_htt_tx_dec_pending(htt);
+ spin_unlock_bh(&ar->htt.tx_lock);
+ ieee80211_free_txskb(ar->hw, skb);
+ return;
+ }
spin_unlock_bh(&ar->htt.tx_lock);
}
ath10k_warn(ar, "failed to transmit frame: %d\n", ret);
if (is_htt) {
spin_lock_bh(&ar->htt.tx_lock);
- ath10k_htt_tx_dec_pending(htt, is_mgmt);
+ ath10k_htt_tx_dec_pending(htt);
+ if (is_mgmt)
+ ath10k_htt_tx_mgmt_dec_pending(htt);
spin_unlock_bh(&ar->htt.tx_lock);
}
return;
spin_unlock_bh(&ar->data_lock);
}
-void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
- const struct htt_tx_done *tx_done)
+int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+ const struct htt_tx_done *tx_done)
{
struct ath10k *ar = htt->ar;
struct device *dev = ar->dev;
struct ath10k_skb_cb *skb_cb;
struct ath10k_txq *artxq;
struct sk_buff *msdu;
- bool limit_mgmt_desc = false;
ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt tx completion msdu_id %u discard %d no_ack %d success %d\n",
if (tx_done->msdu_id >= htt->max_num_pending_tx) {
ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n",
tx_done->msdu_id);
- return;
+ return -EINVAL;
}
spin_lock_bh(&htt->tx_lock);
ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n",
tx_done->msdu_id);
spin_unlock_bh(&htt->tx_lock);
- return;
+ return -ENOENT;
}
skb_cb = ATH10K_SKB_CB(msdu);
txq = skb_cb->txq;
artxq = (void *)txq->drv_priv;
- if (unlikely(skb_cb->flags & ATH10K_SKB_F_MGMT) &&
- ar->hw_params.max_probe_resp_desc_thres)
- limit_mgmt_desc = true;
-
if (txq)
artxq->num_fw_queued--;
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
- ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
+ ath10k_htt_tx_dec_pending(htt);
if (htt->num_pending_tx == 0)
wake_up(&htt->empty_tx_wq);
spin_unlock_bh(&htt->tx_lock);
if (tx_done->discard) {
ieee80211_free_txskb(htt->ar->hw, msdu);
- return;
+ return 0;
}
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
ieee80211_tx_status(htt->ar->hw, msdu);
/* we do not own the msdu anymore */
+ return 0;
}
struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
#include "htt.h"
-void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
- const struct htt_tx_done *tx_done);
+int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+ const struct htt_tx_done *tx_done);
struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
const u8 *addr);