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

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

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
Loading
Loading
Loading
Loading
+2 −10
Original line number Original line Diff line number Diff line
@@ -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)
			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)
	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))) {
+2 −6
Original line number Original line Diff line number Diff line
@@ -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)


	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)


	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);
+8 −9
Original line number Original line Diff line number Diff line
@@ -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,
		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,


	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,


	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,