diff options
| author | Yun Park <yunp@codeaurora.org> | 2016-08-17 16:26:54 -0700 |
|---|---|---|
| committer | qcabuildsw <qcabuildsw@localhost> | 2016-12-08 13:53:20 -0800 |
| commit | fc1b5c47298a3f28caeb4b61072e994619572f84 (patch) | |
| tree | ae2125b7e6bbd90b13601419eaba1e8590021a83 | |
| parent | 97e30fa8b711808e3f834eb5076defd4d3d9751f (diff) | |
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
| -rw-r--r-- | core/dp/htt/htt_tx.c | 72 | ||||
| -rw-r--r-- | core/hdd/inc/wlan_hdd_cfg.h | 2 | ||||
| -rw-r--r-- | core/hdd/src/wlan_hdd_main.c | 30 |
3 files changed, 101 insertions, 3 deletions
diff --git a/core/dp/htt/htt_tx.c b/core/dp/htt/htt_tx.c index a4ca82f154ef..653c838aff39 100644 --- a/core/dp/htt/htt_tx.c +++ b/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 diff --git a/core/hdd/inc/wlan_hdd_cfg.h b/core/hdd/inc/wlan_hdd_cfg.h index 492682348f46..0188a1ea3836 100644 --- a/core/hdd/inc/wlan_hdd_cfg.h +++ b/core/hdd/inc/wlan_hdd_cfg.h @@ -2544,6 +2544,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) @@ -2554,6 +2555,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) diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index a0304a4d47f8..0b31804673be 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -7015,10 +7015,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; |
