aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath10k/htt_rx.c
diff options
context:
space:
mode:
authorMichal Kazior <michal.kazior@tieto.com>2013-09-24 04:18:36 -0400
committerKalle Valo <kvalo@qca.qualcomm.com>2013-09-26 10:22:54 -0400
commit6e712d427cb0542afdd5220edb6e4f4f8a5b952d (patch)
treeab9d056def4b85a1f1214a7feb13ebd277d0af55 /drivers/net/wireless/ath/ath10k/htt_rx.c
parent4d316c79a5dcc13dea8110f0fcf295a17b4b625b (diff)
ath10k: replenish HTT RX buffers in a tasklet
This starves FW RX ring buffer in case of excessive RX. This prevents from CPU being overwhelmed by RX indications/completions by naturally forbiddin FW to submit more RX. This fixes RX starvation on slow machines when under heavy RX traffic. kvalo: remove extra newline Signed-off-by: Michal Kazior <michal.kazior@tieto.com> Signed-off-by: Kalle Valo <kvalo@qca.qualcomm.com>
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/htt_rx.c')
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c35
1 files changed, 32 insertions, 3 deletions
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index c4637f18734f..90d4f74c28d7 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -182,10 +182,27 @@ static int ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num)
182 182
183static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt) 183static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt)
184{ 184{
185 int ret, num_to_fill; 185 int ret, num_deficit, num_to_fill;
186 186
187 /* Refilling the whole RX ring buffer proves to be a bad idea. The
188 * reason is RX may take up significant amount of CPU cycles and starve
189 * other tasks, e.g. TX on an ethernet device while acting as a bridge
190 * with ath10k wlan interface. This ended up with very poor performance
191 * once CPU the host system was overwhelmed with RX on ath10k.
192 *
193 * By limiting the number of refills the replenishing occurs
194 * progressively. This in turns makes use of the fact tasklets are
195 * processed in FIFO order. This means actual RX processing can starve
196 * out refilling. If there's not enough buffers on RX ring FW will not
197 * report RX until it is refilled with enough buffers. This
198 * automatically balances load wrt to CPU power.
199 *
200 * This probably comes at a cost of lower maximum throughput but
201 * improves the avarage and stability. */
187 spin_lock_bh(&htt->rx_ring.lock); 202 spin_lock_bh(&htt->rx_ring.lock);
188 num_to_fill = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt; 203 num_deficit = htt->rx_ring.fill_level - htt->rx_ring.fill_cnt;
204 num_to_fill = min(ATH10K_HTT_MAX_NUM_REFILL, num_deficit);
205 num_deficit -= num_to_fill;
189 ret = ath10k_htt_rx_ring_fill_n(htt, num_to_fill); 206 ret = ath10k_htt_rx_ring_fill_n(htt, num_to_fill);
190 if (ret == -ENOMEM) { 207 if (ret == -ENOMEM) {
191 /* 208 /*
@@ -196,6 +213,8 @@ static void ath10k_htt_rx_msdu_buff_replenish(struct ath10k_htt *htt)
196 */ 213 */
197 mod_timer(&htt->rx_ring.refill_retry_timer, jiffies + 214 mod_timer(&htt->rx_ring.refill_retry_timer, jiffies +
198 msecs_to_jiffies(HTT_RX_RING_REFILL_RETRY_MS)); 215 msecs_to_jiffies(HTT_RX_RING_REFILL_RETRY_MS));
216 } else if (num_deficit > 0) {
217 tasklet_schedule(&htt->rx_replenish_task);
199 } 218 }
200 spin_unlock_bh(&htt->rx_ring.lock); 219 spin_unlock_bh(&htt->rx_ring.lock);
201} 220}
@@ -217,6 +236,7 @@ void ath10k_htt_rx_detach(struct ath10k_htt *htt)
217 int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld; 236 int sw_rd_idx = htt->rx_ring.sw_rd_idx.msdu_payld;
218 237
219 del_timer_sync(&htt->rx_ring.refill_retry_timer); 238 del_timer_sync(&htt->rx_ring.refill_retry_timer);
239 tasklet_kill(&htt->rx_replenish_task);
220 240
221 while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) { 241 while (sw_rd_idx != __le32_to_cpu(*(htt->rx_ring.alloc_idx.vaddr))) {
222 struct sk_buff *skb = 242 struct sk_buff *skb =
@@ -446,6 +466,12 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt,
446 return msdu_chaining; 466 return msdu_chaining;
447} 467}
448 468
469static void ath10k_htt_rx_replenish_task(unsigned long ptr)
470{
471 struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
472 ath10k_htt_rx_msdu_buff_replenish(htt);
473}
474
449int ath10k_htt_rx_attach(struct ath10k_htt *htt) 475int ath10k_htt_rx_attach(struct ath10k_htt *htt)
450{ 476{
451 dma_addr_t paddr; 477 dma_addr_t paddr;
@@ -506,6 +532,9 @@ int ath10k_htt_rx_attach(struct ath10k_htt *htt)
506 if (__ath10k_htt_rx_ring_fill_n(htt, htt->rx_ring.fill_level)) 532 if (__ath10k_htt_rx_ring_fill_n(htt, htt->rx_ring.fill_level))
507 goto err_fill_ring; 533 goto err_fill_ring;
508 534
535 tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task,
536 (unsigned long)htt);
537
509 ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n", 538 ath10k_dbg(ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n",
510 htt->rx_ring.size, htt->rx_ring.fill_level); 539 htt->rx_ring.size, htt->rx_ring.fill_level);
511 return 0; 540 return 0;
@@ -956,7 +985,7 @@ static void ath10k_htt_rx_handler(struct ath10k_htt *htt,
956 } 985 }
957 } 986 }
958 987
959 ath10k_htt_rx_msdu_buff_replenish(htt); 988 tasklet_schedule(&htt->rx_replenish_task);
960} 989}
961 990
962static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt, 991static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt,