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