Commit 005fb161 authored by Qi Zhou's avatar Qi Zhou Committed by Kalle Valo

ath10k: Improve performance by reducing tx_lock contention

During tx completion, tx_lock is held for longer than required, preventing
efficient refill of htt->pending_tx. Refactor the code so that only MSDU
related operations are protected by the lock.

Improves downstream performance on a dual-core ARM Freescale LS1024A
(f.k.a. Mindspeed Comcerto 2000) AP with a 3x3 client from 495 to 580 Mbps.
Other CPU bound multicore systems may also benefit.
Signed-off-by: default avatarDenton Gentry <dgentry@google.com>
Signed-off-by: default avatarAvery Pennarun <apenwarr@google.com>
[mfaltesek@google.com: removed conflicting code for tracking msdu_ids.]
Signed-off-by: default avatarMarty Faltesek <mfaltesek@google.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 3413e97d
...@@ -1631,8 +1631,6 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar, ...@@ -1631,8 +1631,6 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
__le16 msdu_id; __le16 msdu_id;
int i; int i;
lockdep_assert_held(&htt->tx_lock);
switch (status) { switch (status) {
case HTT_DATA_TX_STATUS_NO_ACK: case HTT_DATA_TX_STATUS_NO_ACK:
tx_done.no_ack = true; tx_done.no_ack = true;
...@@ -1998,15 +1996,11 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) ...@@ -1998,15 +1996,11 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break; break;
} }
spin_lock_bh(&htt->tx_lock);
ath10k_txrx_tx_unref(htt, &tx_done); ath10k_txrx_tx_unref(htt, &tx_done);
spin_unlock_bh(&htt->tx_lock);
break; break;
} }
case HTT_T2H_MSG_TYPE_TX_COMPL_IND: case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
spin_lock_bh(&htt->tx_lock); skb_queue_tail(&htt->tx_compl_q, skb);
__skb_queue_tail(&htt->tx_compl_q, skb);
spin_unlock_bh(&htt->tx_lock);
tasklet_schedule(&htt->txrx_compl_task); tasklet_schedule(&htt->txrx_compl_task);
return; return;
case HTT_T2H_MSG_TYPE_SEC_IND: { case HTT_T2H_MSG_TYPE_SEC_IND: {
...@@ -2095,12 +2089,10 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr) ...@@ -2095,12 +2089,10 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr)
struct htt_resp *resp; struct htt_resp *resp;
struct sk_buff *skb; struct sk_buff *skb;
spin_lock_bh(&htt->tx_lock); while ((skb = skb_dequeue(&htt->tx_compl_q))) {
while ((skb = __skb_dequeue(&htt->tx_compl_q))) {
ath10k_htt_rx_frm_tx_compl(htt->ar, skb); ath10k_htt_rx_frm_tx_compl(htt->ar, skb);
dev_kfree_skb_any(skb); dev_kfree_skb_any(skb);
} }
spin_unlock_bh(&htt->tx_lock);
spin_lock_bh(&htt->rx_ring.lock); spin_lock_bh(&htt->rx_ring.lock);
while ((skb = __skb_dequeue(&htt->rx_compl_q))) { while ((skb = __skb_dequeue(&htt->rx_compl_q))) {
......
...@@ -134,9 +134,7 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) ...@@ -134,9 +134,7 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx)
tx_done.discard = 1; tx_done.discard = 1;
tx_done.msdu_id = msdu_id; tx_done.msdu_id = msdu_id;
spin_lock_bh(&htt->tx_lock);
ath10k_txrx_tx_unref(htt, &tx_done); ath10k_txrx_tx_unref(htt, &tx_done);
spin_unlock_bh(&htt->tx_lock);
return 0; return 0;
} }
...@@ -429,12 +427,11 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -429,12 +427,11 @@ 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);
res = ath10k_htt_tx_alloc_msdu_id(htt, msdu); res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
if (res < 0) {
spin_unlock_bh(&htt->tx_lock); spin_unlock_bh(&htt->tx_lock);
if (res < 0) {
goto err_tx_dec; goto err_tx_dec;
} }
msdu_id = res; msdu_id = res;
spin_unlock_bh(&htt->tx_lock);
txdesc = ath10k_htc_alloc_skb(ar, len); txdesc = ath10k_htc_alloc_skb(ar, len);
if (!txdesc) { if (!txdesc) {
...@@ -506,12 +503,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) ...@@ -506,12 +503,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
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);
if (res < 0) {
spin_unlock_bh(&htt->tx_lock); spin_unlock_bh(&htt->tx_lock);
if (res < 0) {
goto err_tx_dec; goto err_tx_dec;
} }
msdu_id = res; msdu_id = res;
spin_unlock_bh(&htt->tx_lock);
prefetch_len = min(htt->prefetch_len, msdu->len); prefetch_len = min(htt->prefetch_len, msdu->len);
prefetch_len = roundup(prefetch_len, 4); prefetch_len = roundup(prefetch_len, 4);
......
...@@ -53,8 +53,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ...@@ -53,8 +53,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
struct ath10k_skb_cb *skb_cb; struct ath10k_skb_cb *skb_cb;
struct sk_buff *msdu; struct sk_buff *msdu;
lockdep_assert_held(&htt->tx_lock);
ath10k_dbg(ar, ATH10K_DBG_HTT, ath10k_dbg(ar, ATH10K_DBG_HTT,
"htt tx completion msdu_id %u discard %d no_ack %d success %d\n", "htt tx completion msdu_id %u discard %d no_ack %d success %d\n",
tx_done->msdu_id, !!tx_done->discard, tx_done->msdu_id, !!tx_done->discard,
...@@ -66,12 +64,19 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ...@@ -66,12 +64,19 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
return; return;
} }
spin_lock_bh(&htt->tx_lock);
msdu = idr_find(&htt->pending_tx, tx_done->msdu_id); msdu = idr_find(&htt->pending_tx, tx_done->msdu_id);
if (!msdu) { if (!msdu) {
ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n", ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n",
tx_done->msdu_id); tx_done->msdu_id);
spin_unlock_bh(&htt->tx_lock);
return; return;
} }
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
__ath10k_htt_tx_dec_pending(htt);
if (htt->num_pending_tx == 0)
wake_up(&htt->empty_tx_wq);
spin_unlock_bh(&htt->tx_lock);
skb_cb = ATH10K_SKB_CB(msdu); skb_cb = ATH10K_SKB_CB(msdu);
...@@ -90,7 +95,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ...@@ -90,7 +95,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
if (tx_done->discard) { if (tx_done->discard) {
ieee80211_free_txskb(htt->ar->hw, msdu); ieee80211_free_txskb(htt->ar->hw, msdu);
goto exit; return;
} }
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
...@@ -104,12 +109,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt, ...@@ -104,12 +109,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
ieee80211_tx_status(htt->ar->hw, msdu); ieee80211_tx_status(htt->ar->hw, msdu);
/* we do not own the msdu anymore */ /* we do not own the msdu anymore */
exit:
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
__ath10k_htt_tx_dec_pending(htt);
if (htt->num_pending_tx == 0)
wake_up(&htt->empty_tx_wq);
} }
struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id, struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
......
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