ath10k: Improve performance by reducing tx_lock contention
authorQi Zhou <qizhou@google.com>
Wed, 22 Jul 2015 20:38:24 +0000 (16:38 -0400)
committerKalle Valo <kvalo@qca.qualcomm.com>
Wed, 29 Jul 2015 08:27:24 +0000 (11:27 +0300)
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: Denton Gentry <dgentry@google.com>
Signed-off-by: Avery Pennarun <apenwarr@google.com>
[mfaltesek@google.com: removed conflicting code for tracking msdu_ids.]
Signed-off-by: Marty Faltesek <mfaltesek@google.com>
Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/htt_tx.c
drivers/net/wireless/ath/ath10k/txrx.c

index 61a26264728aa1ea0a40bb715653cda19681a3f6..5e54c393767e2212ecf6463c2b4113f464bed7d2 100644 (file)
@@ -1631,8 +1631,6 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
        __le16 msdu_id;
        int i;
 
-       lockdep_assert_held(&htt->tx_lock);
-
        switch (status) {
        case HTT_DATA_TX_STATUS_NO_ACK:
                tx_done.no_ack = true;
@@ -1998,15 +1996,11 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
                        break;
                }
 
-               spin_lock_bh(&htt->tx_lock);
                ath10k_txrx_tx_unref(htt, &tx_done);
-               spin_unlock_bh(&htt->tx_lock);
                break;
        }
        case HTT_T2H_MSG_TYPE_TX_COMPL_IND:
-               spin_lock_bh(&htt->tx_lock);
-               __skb_queue_tail(&htt->tx_compl_q, skb);
-               spin_unlock_bh(&htt->tx_lock);
+               skb_queue_tail(&htt->tx_compl_q, skb);
                tasklet_schedule(&htt->txrx_compl_task);
                return;
        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 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);
                dev_kfree_skb_any(skb);
        }
-       spin_unlock_bh(&htt->tx_lock);
 
        spin_lock_bh(&htt->rx_ring.lock);
        while ((skb = __skb_dequeue(&htt->rx_compl_q))) {
index a97dd9d4295bae7c9928ec983ee79c2fb5552bab..2c0627b7141b8c5901db45a5b774f4e8ccb915ce 100644 (file)
@@ -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.msdu_id = msdu_id;
 
-       spin_lock_bh(&htt->tx_lock);
        ath10k_txrx_tx_unref(htt, &tx_done);
-       spin_unlock_bh(&htt->tx_lock);
 
        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);
        res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
+       spin_unlock_bh(&htt->tx_lock);
        if (res < 0) {
-               spin_unlock_bh(&htt->tx_lock);
                goto err_tx_dec;
        }
        msdu_id = res;
-       spin_unlock_bh(&htt->tx_lock);
 
        txdesc = ath10k_htc_alloc_skb(ar, len);
        if (!txdesc) {
@@ -506,12 +503,11 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
 
        spin_lock_bh(&htt->tx_lock);
        res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
+       spin_unlock_bh(&htt->tx_lock);
        if (res < 0) {
-               spin_unlock_bh(&htt->tx_lock);
                goto err_tx_dec;
        }
        msdu_id = res;
-       spin_unlock_bh(&htt->tx_lock);
 
        prefetch_len = min(htt->prefetch_len, msdu->len);
        prefetch_len = roundup(prefetch_len, 4);
index 6cf289158840a3ba01da0f82c81a4e07916a4b70..e4a9c4c8d0cb7e8f7a9a89372e6537d9efc9887e 100644 (file)
@@ -53,8 +53,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
        struct ath10k_skb_cb *skb_cb;
        struct sk_buff *msdu;
 
-       lockdep_assert_held(&htt->tx_lock);
-
        ath10k_dbg(ar, ATH10K_DBG_HTT,
                   "htt tx completion msdu_id %u discard %d no_ack %d success %d\n",
                   tx_done->msdu_id, !!tx_done->discard,
@@ -66,12 +64,19 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
                return;
        }
 
+       spin_lock_bh(&htt->tx_lock);
        msdu = idr_find(&htt->pending_tx, tx_done->msdu_id);
        if (!msdu) {
                ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n",
                            tx_done->msdu_id);
+               spin_unlock_bh(&htt->tx_lock);
                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);
 
@@ -90,7 +95,7 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
 
        if (tx_done->discard) {
                ieee80211_free_txskb(htt->ar->hw, msdu);
-               goto exit;
+               return;
        }
 
        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);
        /* 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,