Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+6 −1
Original line number Original line Diff line number Diff line
@@ -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 *);
+21 −64
Original line number Original line Diff line number Diff line
@@ -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)
		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)
	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)
	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)
	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,
	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,
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;
}
}
+43 −8
Original line number Original line Diff line number Diff line
@@ -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,
			 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,
		}
		}
	}
	}


	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)
	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)
		}
		}


		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,
			     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. */
+1 −1
Original line number Original line Diff line number Diff line
@@ -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);