123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- /*
- * Copyright (c) 2017-2019 The Linux Foundation. All rights reserved.
- *
- * Permission to use, copy, modify, and/or distribute this software for
- * any purpose with or without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
- #include "hal_hw_headers.h"
- #include "dp_types.h"
- #include "qdf_nbuf.h"
- #include "qdf_atomic.h"
- #include "qdf_types.h"
- #include "dp_tx.h"
- #include "dp_tx_desc.h"
- #include "dp_internal.h"
- #ifdef ATH_SUPPORT_IQUE
- #define MAX_ME_BUF_CHUNK 1424
- #define ME_US_TO_SEC(_x) ((_x)/(1000 * 1000))
- #define ME_CLEAN_WAIT_TIMEOUT (200000) /*200ms*/
- #define ME_CLEAN_WAIT_COUNT 400
- /**
- * dp_tx_me_init():Initialize ME buffer ppol
- * @pdev: DP PDEV handle
- *
- * Return:0 on Succes 1 on failure
- */
- static inline uint16_t
- dp_tx_me_init(struct dp_pdev *pdev)
- {
- uint16_t i, mc_uc_buf_len, num_pool_elems;
- uint32_t pool_size;
- struct dp_tx_me_buf_t *p;
- mc_uc_buf_len = sizeof(struct dp_tx_me_buf_t);
- num_pool_elems = MAX_ME_BUF_CHUNK;
- /* Add flow control buffer count */
- pool_size = (mc_uc_buf_len) * num_pool_elems;
- pdev->me_buf.size = mc_uc_buf_len;
- if (!pdev->me_buf.vaddr) {
- qdf_spin_lock_bh(&pdev->tx_mutex);
- pdev->me_buf.vaddr = qdf_mem_malloc(pool_size);
- if (!pdev->me_buf.vaddr) {
- qdf_spin_unlock_bh(&pdev->tx_mutex);
- QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
- "Error allocating memory pool");
- return 1;
- }
- pdev->me_buf.buf_in_use = 0;
- pdev->me_buf.freelist =
- (struct dp_tx_me_buf_t *) pdev->me_buf.vaddr;
- /*
- * me_buf looks like this
- * |=======+==========================|
- * | ptr | Dst MAC |
- * |=======+==========================|
- */
- p = pdev->me_buf.freelist;
- for (i = 0; i < num_pool_elems-1; i++) {
- p->next = (struct dp_tx_me_buf_t *)
- ((char *)p + pdev->me_buf.size);
- p = p->next;
- }
- p->next = NULL;
- qdf_spin_unlock_bh(&pdev->tx_mutex);
- QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
- "ME Pool successfully initialized vaddr - %x \
- paddr - %x\n num_elems = %d buf_size - %d"
- "pool_size = %d",
- pdev->me_buf.vaddr,
- (unsigned int)pdev->me_buf.paddr,
- (unsigned int)num_pool_elems,
- (unsigned int)pdev->me_buf.size,
- (unsigned int)pool_size);
- } else {
- QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
- "ME Already Enabled!!");
- }
- return 0;
- }
- /**
- * dp_tx_me_alloc_descriptor():Allocate ME descriptor
- * @pdev_handle: DP PDEV handle
- *
- * Return:void
- */
- void
- dp_tx_me_alloc_descriptor(struct cdp_pdev *pdev_handle)
- {
- struct dp_pdev *pdev = (struct dp_pdev *) pdev_handle;
- if (qdf_atomic_read(&pdev->mc_num_vap_attached) == 0) {
- dp_tx_me_init(pdev);
- QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
- FL("Enable MCAST_TO_UCAST "));
- }
- qdf_atomic_inc(&pdev->mc_num_vap_attached);
- }
- /**
- * dp_tx_me_exit():Free memory and other cleanup required for
- * multicast unicast conversion
- * @pdev - DP_PDEV handle
- *
- * Return:void
- */
- void
- dp_tx_me_exit(struct dp_pdev *pdev)
- {
- /* Add flow control buffer count */
- uint32_t wait_time = ME_US_TO_SEC(ME_CLEAN_WAIT_TIMEOUT *
- ME_CLEAN_WAIT_COUNT);
- if (pdev->me_buf.vaddr) {
- uint16_t wait_cnt = 0;
- QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
- "Disabling Mcastenhance"
- "This may take some time");
- qdf_spin_lock_bh(&pdev->tx_mutex);
- while ((pdev->me_buf.buf_in_use > 0) &&
- (wait_cnt < ME_CLEAN_WAIT_COUNT)) {
- qdf_spin_unlock_bh(&pdev->tx_mutex);
- OS_SLEEP(ME_CLEAN_WAIT_TIMEOUT);
- wait_cnt++;
- qdf_spin_lock_bh(&pdev->tx_mutex);
- }
- if (pdev->me_buf.buf_in_use > 0) {
- QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
- "Tx-comp pending for %d "
- "ME frames after waiting %ds!!",
- pdev->me_buf.buf_in_use, wait_time);
- qdf_assert_always(0);
- }
- qdf_mem_free(pdev->me_buf.vaddr);
- pdev->me_buf.vaddr = NULL;
- pdev->me_buf.freelist = NULL;
- qdf_spin_unlock_bh(&pdev->tx_mutex);
- } else {
- QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
- "ME Already Disabled !!!");
- }
- }
- /* dp_tx_me_desc_flush() - release me resources associated to tx_desc
- * @pdev: DP_PDEV handle
- *
- * This function will free all outstanding ME buffer
- * for which either free during
- * completion didn't happened or completion is not
- * received.
- */
- void dp_tx_me_desc_flush(struct dp_pdev *pdev)
- {
- uint8_t i, num_pool;
- uint32_t j;
- uint32_t num_desc, page_id, offset;
- uint16_t num_desc_per_page;
- struct dp_soc *soc = pdev->soc;
- struct dp_tx_desc_s *tx_desc = NULL;
- struct dp_tx_desc_pool_s *tx_desc_pool = NULL;
- num_desc = wlan_cfg_get_num_tx_desc(soc->wlan_cfg_ctx);
- num_pool = wlan_cfg_get_num_tx_desc_pool(soc->wlan_cfg_ctx);
- for (i = 0; i < num_pool; i++) {
- tx_desc_pool = &soc->tx_desc[i];
- if (!tx_desc_pool || !tx_desc_pool->desc_pages.cacheable_pages)
- continue;
- num_desc_per_page =
- tx_desc_pool->desc_pages.num_element_per_page;
- for (j = 0; j < num_desc; j++) {
- page_id = j / num_desc_per_page;
- offset = j % num_desc_per_page;
- tx_desc = dp_tx_desc_find(soc, i, page_id, offset);
- if (tx_desc && (tx_desc->pdev == pdev) &&
- (tx_desc->flags & DP_TX_DESC_FLAG_ME) &&
- (tx_desc->flags & DP_TX_DESC_FLAG_ALLOCATED)) {
- dp_tx_comp_free_buf(soc, tx_desc);
- dp_tx_desc_release(tx_desc, i);
- }
- }
- }
- }
- /**
- * dp_tx_me_free_descriptor():free ME descriptor
- * @pdev_handle:DP_PDEV handle
- *
- * Return:void
- */
- void
- dp_tx_me_free_descriptor(struct cdp_pdev *pdev_handle)
- {
- struct dp_pdev *pdev = (struct dp_pdev *) pdev_handle;
- qdf_atomic_dec(&pdev->mc_num_vap_attached);
- if (atomic_read(&pdev->mc_num_vap_attached) == 0) {
- dp_tx_me_desc_flush(pdev);
- dp_tx_me_exit(pdev);
- QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO,
- "Disable MCAST_TO_UCAST");
- }
- }
- /**
- * dp_tx_prepare_send_me(): Call to the umac to get the list of clients
- * @vdev: DP VDEV handle
- * @nbuf: Multicast buffer
- *
- * Return: no of packets transmitted
- */
- QDF_STATUS
- dp_tx_prepare_send_me(struct dp_vdev *vdev, qdf_nbuf_t nbuf)
- {
- if (vdev->me_convert) {
- if (vdev->me_convert(vdev->osif_vdev, nbuf) > 0)
- return QDF_STATUS_SUCCESS;
- }
- return QDF_STATUS_E_FAILURE;
- }
- #endif
|