The real limit for sending htt tx is either
msdu_id storage type (u16 - 65536 different
values) or the HIF tx pipe queue length (2047 in
case of our PCI HIF).

The htt tx pipe does not use interrupts - it must
be polled. It is polled either on RX
unconditionally or on TX if HIF tx pipe has used
over 50% of the resources.

With this patch we should finally trigger the TX
polling properly. What this really means we should
have a smoother tx. Not because the tx limit is
greater, but simply because we'll be triggering
the polling properly in case of heavy tx.

Signed-off-by: Michal Kazior <michal.kaz...@tieto.com>
---
 drivers/net/wireless/ath/ath10k/htt.c    |    7 ++++-
 drivers/net/wireless/ath/ath10k/htt.h    |    9 +++----
 drivers/net/wireless/ath/ath10k/htt_tx.c |   41 +++++++++++++++++++++++++-----
 drivers/net/wireless/ath/ath10k/mac.c    |    2 +-
 drivers/net/wireless/ath/ath10k/txrx.c   |    4 +--
 5 files changed, 47 insertions(+), 16 deletions(-)

diff --git a/drivers/net/wireless/ath/ath10k/htt.c 
b/drivers/net/wireless/ath/ath10k/htt.c
index b39f5de..185a546 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -50,6 +50,7 @@ static int ath10k_htt_htc_attach(struct ath10k_htt *htt)
 struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
 {
        struct ath10k_htt *htt;
+       int ret;
 
        htt = kzalloc(sizeof(*htt), GFP_KERNEL);
        if (!htt)
@@ -67,7 +68,11 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar)
        if (ath10k_htt_htc_attach(htt))
                goto err_htc_attach;
 
-       ath10k_htt_tx_attach(htt);
+       ret = ath10k_htt_tx_attach(htt);
+       if (ret) {
+               ath10k_err("could not attach htt tx (%d)\n", ret);
+               goto err_htc_attach;
+       }
 
        if (ath10k_htt_rx_attach(htt))
                goto err_rx_attach;
diff --git a/drivers/net/wireless/ath/ath10k/htt.h 
b/drivers/net/wireless/ath/ath10k/htt.h
index 8ae1f03..a7a7aa0 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -1184,8 +1184,6 @@ struct htt_rx_info {
        bool fcs_err;
 };
 
-#define HTT_MAX_NUM_PENDING_TX 512 /* FIXME: find proper value? */
-
 struct ath10k_htt {
        struct ath10k *ar;
        enum ath10k_htc_ep_id eid;
@@ -1262,9 +1260,10 @@ struct ath10k_htt {
 
        /* Protects access to %pending_tx, %used_msdu_ids */
        spinlock_t tx_lock;
+       int max_num_pending_tx;
        int num_pending_tx;
-       struct sk_buff *pending_tx[HTT_MAX_NUM_PENDING_TX];
-       DECLARE_BITMAP(used_msdu_ids, HTT_MAX_NUM_PENDING_TX);
+       struct sk_buff **pending_tx;
+       unsigned long *used_msdu_ids; /* bitmap */
        wait_queue_head_t empty_tx_wq;
 
        /* set if host-fw communication goes haywire
@@ -1322,7 +1321,7 @@ struct ath10k_htt *ath10k_htt_attach(struct ath10k *ar);
 int ath10k_htt_attach_target(struct ath10k_htt *htt);
 void ath10k_htt_detach(struct ath10k_htt *htt);
 
-void ath10k_htt_tx_attach(struct ath10k_htt *htt);
+int ath10k_htt_tx_attach(struct ath10k_htt *htt);
 void ath10k_htt_tx_detach(struct ath10k_htt *htt);
 int ath10k_htt_rx_attach(struct ath10k_htt *htt);
 void ath10k_htt_rx_detach(struct ath10k_htt *htt);
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c 
b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 7dd366f..bd84153 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -25,7 +25,7 @@
 void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt)
 {
        htt->num_pending_tx--;
-       if (htt->num_pending_tx == HTT_MAX_NUM_PENDING_TX - 1)
+       if (htt->num_pending_tx == htt->max_num_pending_tx - 1)
                ieee80211_wake_queues(htt->ar->hw);
 }
 
@@ -42,13 +42,13 @@ static int ath10k_htt_tx_inc_pending(struct ath10k_htt *htt)
 
        spin_lock_bh(&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;
                goto exit;
        }
 
        htt->num_pending_tx++;
-       if (htt->num_pending_tx == HTT_MAX_NUM_PENDING_TX)
+       if (htt->num_pending_tx == htt->max_num_pending_tx)
                ieee80211_stop_queues(htt->ar->hw);
 
 exit:
@@ -63,8 +63,8 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt)
        lockdep_assert_held(&htt->tx_lock);
 
        msdu_id = find_first_zero_bit(htt->used_msdu_ids,
-                                     HTT_MAX_NUM_PENDING_TX);
-       if (msdu_id == HTT_MAX_NUM_PENDING_TX)
+                                     htt->max_num_pending_tx);
+       if (msdu_id == htt->max_num_pending_tx)
                return -ENOBUFS;
 
        ath10k_dbg(ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
@@ -83,10 +83,35 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 
msdu_id)
        __clear_bit(msdu_id, htt->used_msdu_ids);
 }
 
-void ath10k_htt_tx_attach(struct ath10k_htt *htt)
+int ath10k_htt_tx_attach(struct ath10k_htt *htt)
 {
+       u8 pipe;
+
        spin_lock_init(&htt->tx_lock);
        init_waitqueue_head(&htt->empty_tx_wq);
+
+       /* At the beginning free queue number should hint us the maximum
+        * queue length */
+       pipe = htt->ar->htc->endpoint[htt->eid].ul_pipe_id;
+       htt->max_num_pending_tx = ath10k_hif_get_free_queue_number(htt->ar, 
pipe);
+
+       ath10k_dbg(ATH10K_DBG_HTT, "htt tx max num pending tx %d\n",
+                  htt->max_num_pending_tx);
+
+       htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) *
+                                 htt->max_num_pending_tx, GFP_KERNEL);
+       if (!htt->pending_tx)
+               return -ENOMEM;
+
+       htt->used_msdu_ids = kzalloc(sizeof(unsigned long) *
+                                    BITS_TO_LONGS(htt->max_num_pending_tx),
+                                    GFP_KERNEL);
+       if (!htt->used_msdu_ids) {
+               kfree(htt->pending_tx);
+               return -ENOMEM;
+       }
+
+       return 0;
 }
 
 static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt *htt)
@@ -97,7 +122,7 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt 
*htt)
        /* No locks needed. Called after communication with the device has
         * been stopped. */
 
-       for (msdu_id = 0; msdu_id < HTT_MAX_NUM_PENDING_TX; msdu_id++) {
+       for (msdu_id = 0; msdu_id < htt->max_num_pending_tx; msdu_id++) {
                if (!test_bit(msdu_id, htt->used_msdu_ids))
                        continue;
 
@@ -119,6 +144,8 @@ static void ath10k_htt_tx_cleanup_pending(struct ath10k_htt 
*htt)
 void ath10k_htt_tx_detach(struct ath10k_htt *htt)
 {
        ath10k_htt_tx_cleanup_pending(htt);
+       kfree(htt->pending_tx);
+       kfree(htt->used_msdu_ids);
        return;
 }
 
diff --git a/drivers/net/wireless/ath/ath10k/mac.c 
b/drivers/net/wireless/ath/ath10k/mac.c
index 974f992..05bf3e9 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -2582,7 +2582,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, u32 
queues, bool drop)
                        bool empty;
                        spin_lock_bh(&ar->htt->tx_lock);
                        empty = bitmap_empty(ar->htt->used_msdu_ids,
-                                            HTT_MAX_NUM_PENDING_TX);
+                                            ar->htt->max_num_pending_tx);
                        spin_unlock_bh(&ar->htt->tx_lock);
                        (empty);
                }), ATH10K_FLUSH_TIMEOUT_HZ);
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c 
b/drivers/net/wireless/ath/ath10k/txrx.c
index ce44ab1..f9d05bd 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -96,7 +96,7 @@ exit:
        htt->pending_tx[ATH10K_SKB_CB(txdesc)->htt.msdu_id] = NULL;
        ath10k_htt_tx_free_msdu_id(htt, ATH10K_SKB_CB(txdesc)->htt.msdu_id);
        __ath10k_htt_tx_dec_pending(htt);
-       if (bitmap_empty(htt->used_msdu_ids, HTT_MAX_NUM_PENDING_TX))
+       if (bitmap_empty(htt->used_msdu_ids, htt->max_num_pending_tx))
                wake_up(&htt->empty_tx_wq);
        spin_unlock_bh(&htt->tx_lock);
 
@@ -111,7 +111,7 @@ void ath10k_txrx_tx_completed(struct ath10k_htt *htt,
        ath10k_dbg(ATH10K_DBG_HTT, "htt tx completion msdu_id %u discard %d 
no_ack %d\n",
                   tx_done->msdu_id, !!tx_done->discard, !!tx_done->no_ack);
 
-       if (tx_done->msdu_id >= ARRAY_SIZE(htt->pending_tx)) {
+       if (tx_done->msdu_id >= htt->max_num_pending_tx) {
                ath10k_warn("warning: msdu_id %d too big, ignoring\n",
                            tx_done->msdu_id);
                return;
-- 
1.7.9.5

_______________________________________________
ath9k-devel mailing list
ath9k-devel@lists.ath9k.org
https://lists.ath9k.org/mailman/listinfo/ath9k-devel

Reply via email to