Quellcode durchsuchen

qcacld-3.0: IPA uC: Round down Tx/Rx buffer count to nearest power of two

qcacld-2.0 to qcacld-3.0 propagation

In certain situation, allocated Tx buffer count could be an arbitrary
number, so not power of two. This could violate F/W ring buffer count
requirement. If allocated Tx buffer count is not power of two, round
down it to the nearest power of two.
The same change is also applicable for INI parameters IpaUcTxBufCount
and IpaUcRxIndRingCount.

Change-Id: I7c119886a669c79adbc7bd9b2c1c1d93de41cf72
CRs-Fixed: 973723
Yun Park vor 8 Jahren
Ursprung
Commit
de38078f7a
3 geänderte Dateien mit 101 neuen und 3 gelöschten Zeilen
  1. 70 2
      core/dp/htt/htt_tx.c
  2. 2 0
      core/hdd/inc/wlan_hdd_cfg.h
  3. 29 1
      core/hdd/src/wlan_hdd_main.c

+ 70 - 2
core/dp/htt/htt_tx.c

@@ -51,6 +51,8 @@
 #include <ol_txrx_internal.h>
 #include <htt_internal.h>
 
+#include <cds_utils.h>
+
 /* IPA Micro controler TX data packet HTT Header Preset */
 /* 31 | 30  29 | 28 | 27 | 26  22  | 21   16 | 15  13   | 12  8      | 7 0
    *----------------------------------------------------------------------------
@@ -1065,10 +1067,12 @@ static int htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t *pdev,
 					  unsigned int uc_tx_partition_base)
 {
 	unsigned int tx_buffer_count;
+	unsigned int  tx_buffer_count_pwr2;
 	void *buffer_vaddr;
 	qdf_dma_addr_t buffer_paddr;
 	uint32_t *header_ptr;
 	qdf_dma_addr_t *ring_vaddr;
+	uint16_t idx;
 
 	ring_vaddr = (qdf_dma_addr_t *)pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr;
 	/* Allocate TX buffers as many as possible */
@@ -1124,7 +1128,38 @@ static int htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t *pdev,
 
 		ring_vaddr++;
 	}
-	return tx_buffer_count;
+
+	/*
+	 * Tx complete ring buffer count should be power of 2.
+	 * So, allocated Tx buffer count should be one less than ring buffer
+	 * size.
+	 */
+	tx_buffer_count_pwr2 = qdf_rounddown_pow_of_two(tx_buffer_count + 1)
+			       - 1;
+	if (tx_buffer_count > tx_buffer_count_pwr2) {
+		qdf_print(
+		    "%s: Allocated Tx buffer count %d is rounded down to %d",
+		    __func__, tx_buffer_count, tx_buffer_count_pwr2);
+
+		/* Free over allocated buffers below power of 2 */
+		for (idx = tx_buffer_count_pwr2; idx < tx_buffer_count; idx++) {
+			if (pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[idx]) {
+			    qdf_mem_free_consistent(
+				pdev->osdev, pdev->osdev->dev,
+				ol_cfg_ipa_uc_tx_buf_size(pdev->ctrl_pdev),
+				pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[idx],
+				pdev->ipa_uc_tx_rsc.paddr_strg[idx], 0);
+			}
+		}
+	}
+
+	if (tx_buffer_count_pwr2 < 0) {
+		qdf_print("%s: Failed to round down Tx buffer count %d",
+				__func__, tx_buffer_count_pwr2);
+		tx_buffer_count_pwr2 = 0;
+	}
+
+	return tx_buffer_count_pwr2;
 }
 #else
 static int htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t *pdev,
@@ -1133,10 +1168,12 @@ static int htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t *pdev,
 					  unsigned int uc_tx_partition_base)
 {
 	unsigned int tx_buffer_count;
+	unsigned int  tx_buffer_count_pwr2;
 	qdf_nbuf_t buffer_vaddr;
 	qdf_dma_addr_t buffer_paddr;
 	uint32_t *header_ptr;
 	uint32_t *ring_vaddr;
+	uint16_t idx;
 
 	ring_vaddr = pdev->ipa_uc_tx_rsc.tx_comp_base.vaddr;
 	/* Allocate TX buffers as many as possible */
@@ -1181,7 +1218,38 @@ static int htt_tx_ipa_uc_wdi_tx_buf_alloc(struct htt_pdev_t *pdev,
 
 		ring_vaddr++;
 	}
-	return tx_buffer_count;
+
+	/*
+	 * Tx complete ring buffer count should be power of 2.
+	 * So, allocated Tx buffer count should be one less than ring buffer
+	 * size.
+	 */
+	tx_buffer_count_pwr2 = qdf_rounddown_pow_of_two(tx_buffer_count + 1)
+			       - 1;
+	if (tx_buffer_count > tx_buffer_count_pwr2) {
+		qdf_print(
+		    "%s: Allocated Tx buffer count %d is rounded down to %d",
+		    __func__, tx_buffer_count, tx_buffer_count_pwr2);
+
+		/* Free over allocated buffers below power of 2 */
+		for (idx = tx_buffer_count_pwr2; idx < tx_buffer_count; idx++) {
+			if (pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[idx]) {
+			    qdf_mem_free_consistent(
+				pdev->osdev, pdev->osdev->dev,
+				ol_cfg_ipa_uc_tx_buf_size(pdev->ctrl_pdev),
+				pdev->ipa_uc_tx_rsc.tx_buf_pool_vaddr_strg[idx],
+				pdev->ipa_uc_tx_rsc.paddr_strg[idx], 0);
+			}
+		}
+	}
+
+	if (tx_buffer_count_pwr2 < 0) {
+		qdf_print("%s: Failed to round down Tx buffer count %d",
+				__func__, tx_buffer_count_pwr2);
+		tx_buffer_count_pwr2 = 0;
+	}
+
+	return tx_buffer_count_pwr2;
 }
 #endif
 

+ 2 - 0
core/hdd/inc/wlan_hdd_cfg.h

@@ -3609,6 +3609,7 @@ typedef enum {
 #define CFG_ROAMING_OFFLOAD_DEFAULT             (1)
 #endif
 
+/* IpaUcTxBufCount should be power of 2 */
 #define CFG_IPA_UC_TX_BUF_COUNT_NAME               "IpaUcTxBufCount"
 #define CFG_IPA_UC_TX_BUF_COUNT_MIN                (0)
 #define CFG_IPA_UC_TX_BUF_COUNT_MAX                (2048)
@@ -3619,6 +3620,7 @@ typedef enum {
 #define CFG_IPA_UC_TX_BUF_SIZE_MAX                (4096)
 #define CFG_IPA_UC_TX_BUF_SIZE_DEFAULT            (2048)
 
+/* IpaUcRxIndRingCount should be power of 2 */
 #define CFG_IPA_UC_RX_IND_RING_COUNT_NAME          "IpaUcRxIndRingCount"
 #define CFG_IPA_UC_RX_IND_RING_COUNT_MIN           (0)
 #define CFG_IPA_UC_RX_IND_RING_COUNT_MAX           (2048)

+ 29 - 1
core/hdd/src/wlan_hdd_main.c

@@ -6983,10 +6983,38 @@ static int hdd_update_cds_config(hdd_context_t *hdd_ctx)
 
 	/* IPA micro controller data path offload resource config item */
 	cds_cfg->uc_offload_enabled = hdd_ipa_uc_is_enabled(hdd_ctx);
+	if (!is_power_of_2(hdd_ctx->config->IpaUcTxBufCount)) {
+		/* IpaUcTxBufCount should be power of 2 */
+		hdd_err("Round down IpaUcTxBufCount %d to nearest power of 2",
+			hdd_ctx->config->IpaUcTxBufCount);
+		hdd_ctx->config->IpaUcTxBufCount =
+			rounddown_pow_of_two(
+				hdd_ctx->config->IpaUcTxBufCount);
+		if (!hdd_ctx->config->IpaUcTxBufCount) {
+			hdd_err("Failed to round down IpaUcTxBufCount");
+			return -EINVAL;
+		}
+		hdd_err("IpaUcTxBufCount rounded down to %d",
+			hdd_ctx->config->IpaUcTxBufCount);
+	}
 	cds_cfg->uc_txbuf_count = hdd_ctx->config->IpaUcTxBufCount;
 	cds_cfg->uc_txbuf_size = hdd_ctx->config->IpaUcTxBufSize;
+	if (!is_power_of_2(hdd_ctx->config->IpaUcRxIndRingCount)) {
+		/* IpaUcRxIndRingCount should be power of 2 */
+		hdd_err("Round down IpaUcRxIndRingCount %d to nearest power of 2",
+			hdd_ctx->config->IpaUcRxIndRingCount);
+		hdd_ctx->config->IpaUcRxIndRingCount =
+			rounddown_pow_of_two(
+				hdd_ctx->config->IpaUcRxIndRingCount);
+		if (!hdd_ctx->config->IpaUcRxIndRingCount) {
+			hdd_err("Failed to round down IpaUcRxIndRingCount");
+			return -EINVAL;
+		}
+		hdd_err("IpaUcRxIndRingCount rounded down to %d",
+			hdd_ctx->config->IpaUcRxIndRingCount);
+	}
 	cds_cfg->uc_rxind_ringcount =
-			hdd_ctx->config->IpaUcRxIndRingCount;
+		hdd_ctx->config->IpaUcRxIndRingCount;
 	cds_cfg->uc_tx_partition_base =
 				hdd_ctx->config->IpaUcTxPartitionBase;
 	cds_cfg->max_scan = hdd_ctx->config->max_scan_count;