blob: 30b7fa5ff53a2aa4c302d65e7bf92aff1108914c [file] [log] [blame]
/*
* Copyright (c) 2020, 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 "dp_types.h"
#include "qdf_mem.h"
#include "qdf_nbuf.h"
#include "cfg_dp.h"
#include "wlan_cfg.h"
#include "dp_types.h"
#include "hal_rx_flow.h"
#include "dp_htt.h"
#include "dp_internal.h"
#ifdef WLAN_SUPPORT_RX_FISA
void dp_rx_dump_fisa_table(struct dp_soc *soc)
{
hal_rx_dump_fse_table(soc->rx_fst->hal_rx_fst);
}
/**
* dp_rx_fst_attach() - Initialize Rx FST and setup necessary parameters
* @soc: SoC handle
* @pdev: Pdev handle
*
* Return: Handle to flow search table entry
*/
QDF_STATUS dp_rx_fst_attach(struct dp_soc *soc, struct dp_pdev *pdev)
{
struct dp_rx_fst *fst;
uint8_t *hash_key;
struct wlan_cfg_dp_soc_ctxt *cfg = soc->wlan_cfg_ctx;
/* Check if it is enabled in the INI */
if (!wlan_cfg_is_rx_fisa_enabled(cfg)) {
dp_err("RX FISA feature is disabled");
return QDF_STATUS_E_NOSUPPORT;
}
#ifdef NOT_YET /* Not required for now */
/* Check if FW supports */
if (!wlan_psoc_nif_fw_ext_cap_get((void *)pdev->ctrl_pdev,
WLAN_SOC_CEXT_RX_FSE_SUPPORT)) {
QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
"rx fse disabled in FW\n");
wlan_cfg_set_rx_flow_tag_enabled(cfg, false);
return QDF_STATUS_E_NOSUPPORT;
}
#endif
if (soc->rx_fst) {
QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
"RX FST already allocated\n");
return QDF_STATUS_SUCCESS;
}
fst = qdf_mem_malloc(sizeof(struct dp_rx_fst));
if (!fst) {
QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
"RX FST allocation failed\n");
return QDF_STATUS_E_NOMEM;
}
fst->max_skid_length = wlan_cfg_rx_fst_get_max_search(cfg);
fst->max_entries = wlan_cfg_get_rx_flow_search_table_size(cfg);
hash_key = wlan_cfg_rx_fst_get_hash_key(cfg);
fst->hash_mask = fst->max_entries - 1;
fst->num_entries = 0;
dp_err("FST setup params FT size %d, hash_mask 0x%x, skid_length %d",
fst->max_entries, fst->hash_mask, fst->max_skid_length);
fst->base = (uint8_t *)qdf_mem_malloc(DP_RX_GET_SW_FT_ENTRY_SIZE *
fst->max_entries);
if (!fst->base) {
QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
"Rx fst->base allocation failed, #entries:%d\n",
fst->max_entries);
goto out2;
}
fst->hal_rx_fst = hal_rx_fst_attach(soc->osdev,
&fst->hal_rx_fst_base_paddr,
fst->max_entries,
fst->max_skid_length, hash_key);
if (qdf_unlikely(!fst->hal_rx_fst)) {
QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
"Rx Hal fst allocation failed, #entries:%d\n",
fst->max_entries);
goto out1;
}
qdf_spinlock_create(&fst->dp_rx_fst_lock);
fst->soc_hdl = soc;
soc->rx_fst = fst;
soc->fisa_enable = true;
QDF_TRACE(QDF_MODULE_ID_ANY, QDF_TRACE_LEVEL_ERROR,
"Rx FST attach successful, #entries:%d\n",
fst->max_entries);
return QDF_STATUS_SUCCESS;
out1:
qdf_mem_free(fst->base);
out2:
qdf_mem_free(fst);
return QDF_STATUS_E_NOMEM;
}
/**
* dp_rx_flow_send_fst_fw_setup() - Program FST parameters in FW/HW post-attach
* @soc: SoC handle
* @pdev: Pdev handle
*
* Return: Success when fst parameters are programmed in FW, error otherwise
*/
QDF_STATUS dp_rx_flow_send_fst_fw_setup(struct dp_soc *soc,
struct dp_pdev *pdev)
{
struct dp_htt_rx_flow_fst_setup fisa_hw_fst_setup_cmd = {0};
struct dp_rx_fst *fst = soc->rx_fst;
struct wlan_cfg_dp_soc_ctxt *cfg = soc->wlan_cfg_ctx;
QDF_STATUS status;
/* mac_id = 0 is used to configure both macs with same FT */
fisa_hw_fst_setup_cmd.pdev_id = 0;
fisa_hw_fst_setup_cmd.max_entries = fst->max_entries;
fisa_hw_fst_setup_cmd.max_search = fst->max_skid_length;
fisa_hw_fst_setup_cmd.base_addr_lo = fst->hal_rx_fst_base_paddr &
0xffffffff;
fisa_hw_fst_setup_cmd.base_addr_hi = (fst->hal_rx_fst_base_paddr >> 32);
fisa_hw_fst_setup_cmd.ip_da_sa_prefix = HTT_RX_IPV4_COMPATIBLE_IPV6;
fisa_hw_fst_setup_cmd.hash_key_len = HAL_FST_HASH_KEY_SIZE_BYTES;
fisa_hw_fst_setup_cmd.hash_key = wlan_cfg_rx_fst_get_hash_key(cfg);
status = dp_htt_rx_flow_fst_setup(pdev, &fisa_hw_fst_setup_cmd);
return status;
}
/**
* dp_rx_fst_detach() - De-initialize Rx FST
* @soc: SoC handle
* @pdev: Pdev handle
*
* Return: None
*/
void dp_rx_fst_detach(struct dp_soc *soc, struct dp_pdev *pdev)
{
struct dp_rx_fst *dp_fst;
dp_fst = soc->rx_fst;
if (qdf_likely(dp_fst)) {
hal_rx_fst_detach(dp_fst->hal_rx_fst, soc->osdev);
qdf_mem_free(dp_fst->base);
qdf_spinlock_destroy(&dp_fst->dp_rx_fst_lock);
qdf_mem_free(dp_fst);
}
soc->rx_fst = NULL;
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG,
"Rx FST detached\n");
}
#else /* WLAN_SUPPORT_RX_FISA */
#endif /* !WLAN_SUPPORT_RX_FISA */