Commit 6421969f authored by Michal Kazior's avatar Michal Kazior Committed by Kalle Valo

ath10k: refactor tx pending management

Tx pending counter logic assumed that the sk_buff
is already known and hence was performed in HTT
functions themselves.

However, for the sake of future wake_tx_queue()
usage the driver must be able to tell whether it
can submit more frames to firmware before it
dequeues frame from ieee80211_txq (and thus long
before HTT Tx functions are called) because once a
frame is dequeued it cannot be requeud back to
mac80211.

This prepares the driver for future changes.
Signed-off-by: default avatarMichal Kazior <michal.kazior@tieto.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent a30c7d00
...@@ -1753,7 +1753,12 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, ...@@ -1753,7 +1753,12 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
u8 max_subfrms_amsdu); u8 max_subfrms_amsdu);
void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb); void ath10k_htt_hif_tx_complete(struct ath10k *ar, struct sk_buff *skb);
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc); 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);
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb); 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); void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *); int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *);
......
...@@ -22,9 +22,12 @@ ...@@ -22,9 +22,12 @@
#include "txrx.h" #include "txrx.h"
#include "debug.h" #include "debug.h"
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc) void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt,
bool is_mgmt)
{ {
if (limit_mgmt_desc) lockdep_assert_held(&htt->tx_lock);
if (is_mgmt)
htt->num_pending_mgmt_tx--; htt->num_pending_mgmt_tx--;
htt->num_pending_tx--; htt->num_pending_tx--;
...@@ -32,43 +35,31 @@ void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc) ...@@ -32,43 +35,31 @@ void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, bool limit_mgmt_desc)
ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL); ath10k_mac_tx_unlock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
} }
static void ath10k_htt_tx_dec_pending(struct ath10k_htt *htt, int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt,
bool limit_mgmt_desc) bool is_mgmt,
{ bool is_presp)
spin_lock_bh(&htt->tx_lock);
__ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
spin_unlock_bh(&htt->tx_lock);
}
static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt,
bool limit_mgmt_desc, bool is_probe_resp)
{ {
struct ath10k *ar = htt->ar; struct ath10k *ar = htt->ar;
int ret = 0;
spin_lock_bh(&htt->tx_lock); lockdep_assert_held(&htt->tx_lock);
if (htt->num_pending_tx >= htt->max_num_pending_tx) { if (htt->num_pending_tx >= htt->max_num_pending_tx)
ret = -EBUSY; return -EBUSY;
goto exit;
}
if (limit_mgmt_desc) { if (is_mgmt &&
if (is_probe_resp && (htt->num_pending_mgmt_tx > is_presp &&
ar->hw_params.max_probe_resp_desc_thres)) { ar->hw_params.max_probe_resp_desc_thres &&
ret = -EBUSY; ar->hw_params.max_probe_resp_desc_thres < htt->num_pending_mgmt_tx)
goto exit; return -EBUSY;
}
if (is_mgmt)
htt->num_pending_mgmt_tx++; htt->num_pending_mgmt_tx++;
}
htt->num_pending_tx++; htt->num_pending_tx++;
if (htt->num_pending_tx == htt->max_num_pending_tx) if (htt->num_pending_tx == htt->max_num_pending_tx)
ath10k_mac_tx_lock(htt->ar, ATH10K_TX_PAUSE_Q_FULL); ath10k_mac_tx_lock(htt->ar, ATH10K_TX_PAUSE_Q_FULL);
exit: return 0;
spin_unlock_bh(&htt->tx_lock);
return ret;
} }
int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb) int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb)
...@@ -576,20 +567,6 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -576,20 +567,6 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
int msdu_id = -1; int msdu_id = -1;
int res; int res;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
bool limit_mgmt_desc = false;
bool is_probe_resp = false;
if (ar->hw_params.max_probe_resp_desc_thres) {
limit_mgmt_desc = true;
if (ieee80211_is_probe_resp(hdr->frame_control))
is_probe_resp = true;
}
res = ath10k_htt_tx_inc_pending(htt, limit_mgmt_desc, is_probe_resp);
if (res)
goto err;
len += sizeof(cmd->hdr); len += sizeof(cmd->hdr);
len += sizeof(cmd->mgmt_tx); len += sizeof(cmd->mgmt_tx);
...@@ -598,7 +575,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -598,7 +575,7 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
spin_unlock_bh(&htt->tx_lock); spin_unlock_bh(&htt->tx_lock);
if (res < 0) if (res < 0)
goto err_tx_dec; goto err;
msdu_id = res; msdu_id = res;
...@@ -649,8 +626,6 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -649,8 +626,6 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
spin_lock_bh(&htt->tx_lock); spin_lock_bh(&htt->tx_lock);
ath10k_htt_tx_free_msdu_id(htt, msdu_id); ath10k_htt_tx_free_msdu_id(htt, msdu_id);
spin_unlock_bh(&htt->tx_lock); spin_unlock_bh(&htt->tx_lock);
err_tx_dec:
ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
err: err:
return res; return res;
} }
...@@ -677,26 +652,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode, ...@@ -677,26 +652,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
u32 frags_paddr = 0; u32 frags_paddr = 0;
u32 txbuf_paddr; u32 txbuf_paddr;
struct htt_msdu_ext_desc *ext_desc = NULL; struct htt_msdu_ext_desc *ext_desc = NULL;
bool limit_mgmt_desc = false;
bool is_probe_resp = false;
if (unlikely(ieee80211_is_mgmt(hdr->frame_control)) &&
ar->hw_params.max_probe_resp_desc_thres) {
limit_mgmt_desc = true;
if (ieee80211_is_probe_resp(hdr->frame_control))
is_probe_resp = true;
}
res = ath10k_htt_tx_inc_pending(htt, limit_mgmt_desc, is_probe_resp);
if (res)
goto err;
spin_lock_bh(&htt->tx_lock); spin_lock_bh(&htt->tx_lock);
res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
spin_unlock_bh(&htt->tx_lock); spin_unlock_bh(&htt->tx_lock);
if (res < 0) if (res < 0)
goto err_tx_dec; goto err;
msdu_id = res; msdu_id = res;
...@@ -862,11 +823,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode, ...@@ -862,11 +823,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, enum ath10k_hw_txrx_mode txmode,
err_unmap_msdu: err_unmap_msdu:
dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE); dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
err_free_msdu_id: err_free_msdu_id:
spin_lock_bh(&htt->tx_lock);
ath10k_htt_tx_free_msdu_id(htt, msdu_id); ath10k_htt_tx_free_msdu_id(htt, msdu_id);
spin_unlock_bh(&htt->tx_lock);
err_tx_dec:
ath10k_htt_tx_dec_pending(htt, limit_mgmt_desc);
err: err:
return res; return res;
} }
...@@ -3358,13 +3358,11 @@ ath10k_mac_tx_h_get_txpath(struct ath10k *ar, ...@@ -3358,13 +3358,11 @@ ath10k_mac_tx_h_get_txpath(struct ath10k *ar,
static int ath10k_mac_tx_submit(struct ath10k *ar, static int ath10k_mac_tx_submit(struct ath10k *ar,
enum ath10k_hw_txrx_mode txmode, enum ath10k_hw_txrx_mode txmode,
enum ath10k_mac_tx_path txpath,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ath10k_htt *htt = &ar->htt; struct ath10k_htt *htt = &ar->htt;
enum ath10k_mac_tx_path txpath; int ret = -EINVAL;
int ret;
txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
switch (txpath) { switch (txpath) {
case ATH10K_MAC_TX_HTT: case ATH10K_MAC_TX_HTT:
...@@ -3398,6 +3396,7 @@ static int ath10k_mac_tx(struct ath10k *ar, ...@@ -3398,6 +3396,7 @@ static int ath10k_mac_tx(struct ath10k *ar,
struct ieee80211_vif *vif, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct ieee80211_sta *sta,
enum ath10k_hw_txrx_mode txmode, enum ath10k_hw_txrx_mode txmode,
enum ath10k_mac_tx_path txpath,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ieee80211_hw *hw = ar->hw; struct ieee80211_hw *hw = ar->hw;
...@@ -3437,7 +3436,7 @@ static int ath10k_mac_tx(struct ath10k *ar, ...@@ -3437,7 +3436,7 @@ static int ath10k_mac_tx(struct ath10k *ar,
} }
} }
ret = ath10k_mac_tx_submit(ar, txmode, skb); ret = ath10k_mac_tx_submit(ar, txmode, txpath, skb);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to submit frame: %d\n", ret); ath10k_warn(ar, "failed to submit frame: %d\n", ret);
return ret; return ret;
...@@ -3465,6 +3464,7 @@ void ath10k_offchan_tx_work(struct work_struct *work) ...@@ -3465,6 +3464,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
struct ath10k_peer *peer; struct ath10k_peer *peer;
struct ath10k_vif *arvif; struct ath10k_vif *arvif;
enum ath10k_hw_txrx_mode txmode; enum ath10k_hw_txrx_mode txmode;
enum ath10k_mac_tx_path txpath;
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
struct ieee80211_vif *vif; struct ieee80211_vif *vif;
struct ieee80211_sta *sta; struct ieee80211_sta *sta;
...@@ -3533,8 +3533,9 @@ void ath10k_offchan_tx_work(struct work_struct *work) ...@@ -3533,8 +3533,9 @@ void ath10k_offchan_tx_work(struct work_struct *work)
} }
txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb); txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
ret = ath10k_mac_tx(ar, vif, sta, txmode, skb); ret = ath10k_mac_tx(ar, vif, sta, txmode, txpath, skb);
if (ret) { if (ret) {
ath10k_warn(ar, "failed to transmit offchannel frame: %d\n", ath10k_warn(ar, "failed to transmit offchannel frame: %d\n",
ret); ret);
...@@ -3758,19 +3759,53 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw, ...@@ -3758,19 +3759,53 @@ static void ath10k_mac_op_tx(struct ieee80211_hw *hw,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct ath10k *ar = hw->priv; struct ath10k *ar = hw->priv;
struct ath10k_htt *htt = &ar->htt;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif; struct ieee80211_vif *vif = info->control.vif;
struct ieee80211_sta *sta = control->sta; struct ieee80211_sta *sta = control->sta;
struct ieee80211_hdr *hdr = (void *)skb->data;
enum ath10k_hw_txrx_mode txmode; enum ath10k_hw_txrx_mode txmode;
enum ath10k_mac_tx_path txpath;
bool is_htt;
bool is_mgmt;
bool is_presp;
int ret; int ret;
ath10k_mac_tx_h_fill_cb(ar, vif, skb); ath10k_mac_tx_h_fill_cb(ar, vif, skb);
txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb); txmode = ath10k_mac_tx_h_get_txmode(ar, vif, sta, skb);
txpath = ath10k_mac_tx_h_get_txpath(ar, skb, txmode);
is_htt = (txpath == ATH10K_MAC_TX_HTT ||
txpath == ATH10K_MAC_TX_HTT_MGMT);
ret = ath10k_mac_tx(ar, vif, sta, txmode, skb); if (is_htt) {
if (ret) 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);
if (ret) {
ath10k_warn(ar, "failed to increase tx pending count: %d, dropping\n",
ret);
spin_unlock_bh(&ar->htt.tx_lock);
ieee80211_free_txskb(ar->hw, skb);
return;
}
spin_unlock_bh(&ar->htt.tx_lock);
}
ret = ath10k_mac_tx(ar, vif, sta, txmode, txpath, skb);
if (ret) {
ath10k_warn(ar, "failed to transmit frame: %d\n", ret); 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);
spin_unlock_bh(&ar->htt.tx_lock);
}
return;
}
} }
/* Must not be called with conf_mutex held as workers can use that also. */ /* Must not be called with conf_mutex held as workers can use that also. */
......
...@@ -86,7 +86,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ...@@ -86,7 +86,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
limit_mgmt_desc = true; limit_mgmt_desc = true;
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id); 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, limit_mgmt_desc);
if (htt->num_pending_tx == 0) if (htt->num_pending_tx == 0)
wake_up(&htt->empty_tx_wq); wake_up(&htt->empty_tx_wq);
spin_unlock_bh(&htt->tx_lock); spin_unlock_bh(&htt->tx_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment