summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohit Khanna <mkhannaqca@codeaurora.org>2017-01-31 21:07:12 -0800
committerqcabuildsw <qcabuildsw@localhost>2017-02-06 20:33:44 -0800
commitc11aa0ed9643b69d03c80e98e3480b501ca7da77 (patch)
tree5dbaa07a2abde493e40f4af7e62162771ad8b26f
parentba6cbda4e5aa952108d60c67c96b8d8ea8eb81c4 (diff)
qcacld-3.0: Enhance htt_rx_ring_fill_n processing
Enhance htt_rx_ring_fill_n by: - Start timer in case the function is not able to find memory to fill rx buffers. - Handle case where one stream can starve the other stream by constantly adding to the debt. CRs-Fixed: 2001325 Change-Id: Idff33d9c28daaf7a00334134459a3633f5ccde7c
-rw-r--r--core/dp/htt/htt_internal.h17
-rw-r--r--core/dp/htt/htt_rx.c170
-rw-r--r--core/dp/htt/htt_types.h3
-rw-r--r--core/hdd/src/wlan_hdd_main.c1
4 files changed, 115 insertions, 76 deletions
diff --git a/core/dp/htt/htt_internal.h b/core/dp/htt/htt_internal.h
index a68405680de5..b8d427f35605 100644
--- a/core/dp/htt/htt_internal.h
+++ b/core/dp/htt/htt_internal.h
@@ -655,7 +655,7 @@ void htt_rx_dbg_rxbuf_init(struct htt_pdev_t *pdev)
pdev->rx_buff_recvd_err = 0;
pdev->refill_retry_timer_starts = 0;
pdev->refill_retry_timer_calls = 0;
-
+ pdev->refill_retry_timer_doubles = 0;
}
}
@@ -679,16 +679,21 @@ static inline int htt_display_rx_buf_debug(struct htt_pdev_t *pdev)
buf[i].posted,
buf[i].recved);
}
+
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
- "rxbuf_idx %d all_posted: %d all_recvd: %d recv_err: %d timer_starts :%d timer_calls :%d",
+ "rxbuf_idx %d all_posted: %d all_recvd: %d recv_err: %d",
pdev->rx_buff_index,
pdev->rx_buff_posted_cum,
pdev->rx_buff_recvd_cum,
- pdev->rx_buff_recvd_err,
- pdev->refill_retry_timer_starts,
- pdev->refill_retry_timer_calls);
-
+ pdev->rx_buff_recvd_err);
+ QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
+ "timer kicks :%d actual :%d restarts:%d debtors: %d fill_n: %d",
+ pdev->refill_retry_timer_starts,
+ pdev->refill_retry_timer_calls,
+ pdev->refill_retry_timer_doubles,
+ pdev->rx_buff_debt_invoked,
+ pdev->rx_buff_fill_n_invoked);
} else
return -EINVAL;
return 0;
diff --git a/core/dp/htt/htt_rx.c b/core/dp/htt/htt_rx.c
index a752d639a26f..26db4b2273af 100644
--- a/core/dp/htt/htt_rx.c
+++ b/core/dp/htt/htt_rx.c
@@ -410,73 +410,6 @@ htt_rx_in_ord_paddr_get(uint32_t *u32p)
#endif /* HELIUMPLUS_PADDR64 */
#endif /* CONFIG_HL_SUPPORT*/
-#ifndef CONFIG_HL_SUPPORT
-
-static int htt_rx_ring_size(struct htt_pdev_t *pdev)
-{
- int size;
-
- /*
- * It is expected that the host CPU will typically be able to service
- * the rx indication from one A-MPDU before the rx indication from
- * the subsequent A-MPDU happens, roughly 1-2 ms later.
- * However, the rx ring should be sized very conservatively, to
- * accomodate the worst reasonable delay before the host CPU services
- * a rx indication interrupt.
- * The rx ring need not be kept full of empty buffers. In theory,
- * the htt host SW can dynamically track the low-water mark in the
- * rx ring, and dynamically adjust the level to which the rx ring
- * is filled with empty buffers, to dynamically meet the desired
- * low-water mark.
- * In contrast, it's difficult to resize the rx ring itself, once
- * it's in use.
- * Thus, the ring itself should be sized very conservatively, while
- * the degree to which the ring is filled with empty buffers should
- * be sized moderately conservatively.
- */
- size =
- ol_cfg_max_thruput_mbps(pdev->ctrl_pdev) *
- 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ /
- (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_MAX_MS;
-
- if (size < HTT_RX_RING_SIZE_MIN)
- size = HTT_RX_RING_SIZE_MIN;
- else if (size > HTT_RX_RING_SIZE_MAX)
- size = HTT_RX_RING_SIZE_MAX;
-
- size = qdf_get_pwr2(size);
- return size;
-}
-
-static int htt_rx_ring_fill_level(struct htt_pdev_t *pdev)
-{
- int size;
-
- size = ol_cfg_max_thruput_mbps(pdev->ctrl_pdev) *
- 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ /
- (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_WORST_LIKELY_MS;
-
- size = qdf_get_pwr2(size);
- /*
- * Make sure the fill level is at least 1 less than the ring size.
- * Leaving 1 element empty allows the SW to easily distinguish
- * between a full ring vs. an empty ring.
- */
- if (size >= pdev->rx_ring.size)
- size = pdev->rx_ring.size - 1;
-
- return size;
-}
-
-static void htt_rx_ring_refill_retry(void *arg)
-{
- htt_pdev_handle pdev = (htt_pdev_handle) arg;
-
- pdev->refill_retry_timer_calls++;
- htt_rx_msdu_buff_replenish(pdev);
-}
-#endif
-
/* full_reorder_offload case: this function is called with lock held */
static int htt_rx_ring_fill_n(struct htt_pdev_t *pdev, int num)
{
@@ -484,6 +417,7 @@ static int htt_rx_ring_fill_n(struct htt_pdev_t *pdev, int num)
QDF_STATUS status;
struct htt_host_rx_desc_base *rx_desc;
int filled = 0;
+ int debt_served = 0;
idx = *(pdev->rx_ring.alloc_idx.vaddr);
@@ -578,10 +512,9 @@ moretofill:
filled++;
idx &= pdev->rx_ring.size_mask;
}
- if (qdf_atomic_read(&pdev->rx_ring.refill_debt) > 0) {
+ if (debt_served < qdf_atomic_read(&pdev->rx_ring.refill_debt)) {
num = qdf_atomic_read(&pdev->rx_ring.refill_debt);
- /* Ideally the following gives 0, but sub is safer */
- qdf_atomic_sub(num, &pdev->rx_ring.refill_debt);
+ debt_served += num;
goto moretofill;
}
@@ -592,6 +525,94 @@ fail:
return filled;
}
+
+#ifndef CONFIG_HL_SUPPORT
+
+static int htt_rx_ring_size(struct htt_pdev_t *pdev)
+{
+ int size;
+
+ /*
+ * It is expected that the host CPU will typically be able to service
+ * the rx indication from one A-MPDU before the rx indication from
+ * the subsequent A-MPDU happens, roughly 1-2 ms later.
+ * However, the rx ring should be sized very conservatively, to
+ * accommodate the worst reasonable delay before the host CPU services
+ * a rx indication interrupt.
+ * The rx ring need not be kept full of empty buffers. In theory,
+ * the htt host SW can dynamically track the low-water mark in the
+ * rx ring, and dynamically adjust the level to which the rx ring
+ * is filled with empty buffers, to dynamically meet the desired
+ * low-water mark.
+ * In contrast, it's difficult to resize the rx ring itself, once
+ * it's in use.
+ * Thus, the ring itself should be sized very conservatively, while
+ * the degree to which the ring is filled with empty buffers should
+ * be sized moderately conservatively.
+ */
+ size =
+ ol_cfg_max_thruput_mbps(pdev->ctrl_pdev) *
+ 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ /
+ (8 * HTT_RX_AVG_FRM_BYTES) * HTT_RX_HOST_LATENCY_MAX_MS;
+
+ if (size < HTT_RX_RING_SIZE_MIN)
+ size = HTT_RX_RING_SIZE_MIN;
+ else if (size > HTT_RX_RING_SIZE_MAX)
+ size = HTT_RX_RING_SIZE_MAX;
+
+ size = qdf_get_pwr2(size);
+ return size;
+}
+
+static int htt_rx_ring_fill_level(struct htt_pdev_t *pdev)
+{
+ int size;
+
+ size = ol_cfg_max_thruput_mbps(pdev->ctrl_pdev) *
+ 1000 /* 1e6 bps/mbps / 1e3 ms per sec = 1000 */ /
+ (8 * HTT_RX_AVG_FRM_BYTES) *
+ HTT_RX_HOST_LATENCY_WORST_LIKELY_MS;
+
+ size = qdf_get_pwr2(size);
+ /*
+ * Make sure the fill level is at least 1 less than the ring size.
+ * Leaving 1 element empty allows the SW to easily distinguish
+ * between a full ring vs. an empty ring.
+ */
+ if (size >= pdev->rx_ring.size)
+ size = pdev->rx_ring.size - 1;
+
+ return size;
+}
+
+static void htt_rx_ring_refill_retry(void *arg)
+{
+ htt_pdev_handle pdev = (htt_pdev_handle) arg;
+ int filled = 0;
+ int num;
+
+ pdev->refill_retry_timer_calls++;
+ qdf_spin_lock_bh(&(pdev->rx_ring.refill_lock));
+
+ num = qdf_atomic_read(&pdev->rx_ring.refill_debt);
+ qdf_atomic_sub(num, &pdev->rx_ring.refill_debt);
+ filled = htt_rx_ring_fill_n(pdev, num);
+
+ qdf_spin_unlock_bh(&(pdev->rx_ring.refill_lock));
+
+ if (filled > num) {
+ /* we served ourselves and some other debt */
+ /* sub is safer than = 0 */
+ qdf_atomic_sub(filled - num, &pdev->rx_ring.refill_debt);
+ } else if (num == filled) { /* nothing to be done */
+ } else {
+ /* we could not fill all, timer must have been started */
+ pdev->refill_retry_timer_doubles++;
+ }
+
+}
+#endif
+
static inline unsigned htt_rx_ring_elems(struct htt_pdev_t *pdev)
{
return
@@ -2898,6 +2919,7 @@ int htt_rx_msdu_buff_in_order_replenish(htt_pdev_handle pdev, uint32_t num)
if (qdf_atomic_read(&pdev->rx_ring.refill_debt)
< RX_RING_REFILL_DEBT_MAX) {
qdf_atomic_add(num, &pdev->rx_ring.refill_debt);
+ pdev->rx_buff_debt_invoked++;
return filled; /* 0 */
}
/*
@@ -2908,9 +2930,17 @@ int htt_rx_msdu_buff_in_order_replenish(htt_pdev_handle pdev, uint32_t num)
*/
qdf_spin_lock_bh(&(pdev->rx_ring.refill_lock));
}
+ pdev->rx_buff_fill_n_invoked++;
filled = htt_rx_ring_fill_n(pdev, num);
+
qdf_spin_unlock_bh(&(pdev->rx_ring.refill_lock));
+ if (filled > num) {
+ /* we served ourselves and some other debt */
+ /* sub is safer than = 0 */
+ qdf_atomic_sub(filled - num, &pdev->rx_ring.refill_debt);
+ }
+
return filled;
}
diff --git a/core/dp/htt/htt_types.h b/core/dp/htt/htt_types.h
index 866b42a57b29..caa0ca455347 100644
--- a/core/dp/htt/htt_types.h
+++ b/core/dp/htt/htt_types.h
@@ -418,8 +418,11 @@ struct htt_pdev_t {
int rx_buff_posted_cum;
int rx_buff_recvd_cum;
int rx_buff_recvd_err;
+ int rx_buff_debt_invoked;
+ int rx_buff_fill_n_invoked;
int refill_retry_timer_starts;
int refill_retry_timer_calls;
+ int refill_retry_timer_doubles;
#endif
/* callback function for packetdump */
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index 7eafacf5b973..5ac1a966e02d 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -5706,6 +5706,7 @@ void wlan_hdd_display_tx_rx_histogram(hdd_context_t *hdd_ctx)
hdd_ctx->hdd_txrx_hist[i].
next_tx_level));
}
+
return;
}