From 9946d36d190192f8f5fcf13bcac69cb45f4edce4 Mon Sep 17 00:00:00 2001 From: Padma Raghunathan Date: Tue, 3 Mar 2020 10:46:56 +0530 Subject: [PATCH] qcacmn: Add CFR feature support Add CFR feature support for WIN and MCL. Change-Id: I135409c00df953ad7ae4e570418403b11ebc1bc7 CRs-Fixed: 2639069 --- target_if/cfr/inc/target_if_cfr.h | 167 ++ target_if/cfr/inc/target_if_cfr_6018.h | 335 ++++ target_if/cfr/src/target_if_cfr.c | 362 ++++ target_if/cfr/src/target_if_cfr_6018.c | 1618 ++++++++++++++++++ umac/cfr/core/inc/cfr_defs_i.h | 133 ++ umac/cfr/core/src/cfr_common.c | 323 ++++ umac/cfr/dispatcher/inc/wlan_cfr_tgt_api.h | 169 ++ umac/cfr/dispatcher/inc/wlan_cfr_ucfg_api.h | 267 +++ umac/cfr/dispatcher/inc/wlan_cfr_utils_api.h | 583 +++++++ umac/cfr/dispatcher/src/wlan_cfr_tgt_api.c | 287 ++++ umac/cfr/dispatcher/src/wlan_cfr_ucfg_api.c | 1104 ++++++++++++ umac/cfr/dispatcher/src/wlan_cfr_utils_api.c | 184 ++ 12 files changed, 5532 insertions(+) create mode 100644 target_if/cfr/inc/target_if_cfr.h create mode 100644 target_if/cfr/inc/target_if_cfr_6018.h create mode 100644 target_if/cfr/src/target_if_cfr.c create mode 100644 target_if/cfr/src/target_if_cfr_6018.c create mode 100644 umac/cfr/core/inc/cfr_defs_i.h create mode 100644 umac/cfr/core/src/cfr_common.c create mode 100644 umac/cfr/dispatcher/inc/wlan_cfr_tgt_api.h create mode 100644 umac/cfr/dispatcher/inc/wlan_cfr_ucfg_api.h create mode 100644 umac/cfr/dispatcher/inc/wlan_cfr_utils_api.h create mode 100644 umac/cfr/dispatcher/src/wlan_cfr_tgt_api.c create mode 100644 umac/cfr/dispatcher/src/wlan_cfr_ucfg_api.c create mode 100644 umac/cfr/dispatcher/src/wlan_cfr_utils_api.c diff --git a/target_if/cfr/inc/target_if_cfr.h b/target_if/cfr/inc/target_if_cfr.h new file mode 100644 index 000000000000..d1533ffdcec1 --- /dev/null +++ b/target_if/cfr/inc/target_if_cfr.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _TARGET_IF_CFR_H_ +#define _TARGET_IF_CFR_H_ + +#include +#include +#include +#include +#include + +#include "wmi_unified_cfr_api.h" +#include "wmi_unified_param.h" +#include "wmi_unified_cfr_param.h" +#define PEER_CFR_CAPTURE_ENABLE 1 +#define PEER_CFR_CAPTURE_DISABLE 0 + +#define PEER_CFR_CAPTURE_EVT_STATUS_MASK 0x80000000 +#define PEER_CFR_CAPTURE_EVT_PS_STATUS_MASK 0x40000000 +#define CFR_TX_EVT_STATUS_MASK 0x00000003 + +/* Status codes used by correlate and relay function */ +#define STATUS_STREAM_AND_RELEASE 0 +#define STATUS_HOLD 1 +#define STATUS_ERROR -1 + +/* Module IDs using corrlation function */ +#define CORRELATE_DBR_MODULE_ID 0 +/* + * HKV2 - Tx completion event for one-shot capture + * Cypress - Tx completion event for one-shot capture (or) RXTLV event for RCC + */ +#define CORRELATE_TX_EV_MODULE_ID 1 + +/** + * target_if_cfr_init_pdev() - Inits cfr pdev and registers necessary handlers. + * @psoc: pointer to psoc object + * @pdev: pointer to pdev object + * + * Return: Registration status for necessary handlers + */ +int target_if_cfr_init_pdev(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev); + +/** + * target_if_cfr_deinit_pdev() - De-inits corresponding pdev and handlers. + * @psoc: pointer to psoc object + * @pdev: pointer to pdev object + * + * Return: De-registration status for necessary handlers + */ +int target_if_cfr_deinit_pdev(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev); + +/** + * target_if_cfr_tx_ops_register() - Registers tx ops for cfr module + * @tx_ops - pointer to tx_ops structure. + */ +void target_if_cfr_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops); + +/** + * target_if_cfr_enable_cfr_timer() - Enables cfr timer + * @pdev: pointer to pdev object + * @cfr_timer: Amount of time this timer has to run + * + * Return: status of timer + */ +int target_if_cfr_enable_cfr_timer(struct wlan_objmgr_pdev *pdev, + uint32_t cfr_timer); + +/** + * target_if_cfr_pdev_set_param() - Function to set params for cfr config + * @pdev: pointer to pdev object + * @param_id: param id which has to be set + * @param_value: value of param being set + * + * Return: success/failure of setting param + */ +int target_if_cfr_pdev_set_param(struct wlan_objmgr_pdev *pdev, + uint32_t param_id, uint32_t param_value); +/** + * target_if_cfr_start_capture() - Function to start cfr capture for a peer + * @pdev: pointer to pdev object + * @peer: pointer to peer object + * @cfr_params: capture parameters for this peer + * + * Return: success/failure status of start capture + */ +int target_if_cfr_start_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer, + struct cfr_capture_params *cfr_params); +/** + * target_if_cfr_stop_capture() - Function to stop cfr capture for a peer + * @pdev: pointer to pdev object + * @peer: pointer to peer object + * + * Return: success/failure status of stop capture + */ +int target_if_cfr_stop_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer); + +/** + * target_if_cfr_get_target_type() - Function to get target type + * @psoc: pointer to psoc object + * + * Return: target type of target + */ +int target_if_cfr_get_target_type(struct wlan_objmgr_psoc *psoc); + +/** + * target_if_cfr_set_cfr_support() - Function to set cfr support + * @psoc: pointer to psoc object + * @value: value to be set + */ +void target_if_cfr_set_cfr_support(struct wlan_objmgr_psoc *psoc, + uint8_t value); + +/** + * target_if_cfr_info_send() - Function to send cfr info to upper layers + * @pdev: pointer to pdev object + * @head: pointer to cfr info head + * @hlen: head len + * @data: pointer to cfr info data + * @dlen: data len + * @tail: pointer to cfr info tail + * @tlen: tail len + */ +void target_if_cfr_info_send(struct wlan_objmgr_pdev *pdev, void *head, + size_t hlen, void *data, size_t dlen, void *tail, + size_t tlen); + +/** + * cfr_wifi2_0_init_pdev() - Function to init legacy pdev + * @psoc: pointer to psoc object + * @pdev: pointer to pdev object + * + * Return: success/failure status of init + */ +QDF_STATUS cfr_wifi2_0_init_pdev(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev); + +/** + * cfr_wifi2_0_deinit_pdev() - Function to deinit legacy pdev + * @psoc: pointer to psoc object + * @pdev: pointer to pdev object + * + * Return: success/failure status of deinit + */ +QDF_STATUS cfr_wifi2_0_deinit_pdev(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev); +#endif diff --git a/target_if/cfr/inc/target_if_cfr_6018.h b/target_if/cfr/inc/target_if_cfr_6018.h new file mode 100644 index 000000000000..4255f85acac9 --- /dev/null +++ b/target_if/cfr/inc/target_if_cfr_6018.h @@ -0,0 +1,335 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _TARGET_IF_CFR_6018_H_ +#define _TARGET_IF_CFR_6018_H_ + +#ifdef WLAN_ENH_CFR_ENABLE +/* + * Memory requirements : + * + * 1. DMA header : + * + * Legacy DMA header(QCA8074V2) : 2 words (length = 8 bytes) + * Enhanced DMA header(QCA6018) : Upto 16 words depending on no. of MU users + * in UL-MU-PPDU (Max length = 64 bytes) + * + * Fixed 4 words for whal_cfir_enhanced_hdr + freeze TLV + * + uplink_user_info TLV (MAX 4) + * + * mu_rx_num_users -> No. of words in CFR DMA header + * 0 -> 12 = 4 + 7(freeze TLV) + 1(for 64-bit alignment) + * 1 -> 12 = 4 + 7(freeze TLV) + 1(user1) + * 2 -> 14 = 4 + 7(freeze TLV) + 2(users 1,2) + 1(for 64-bit alignment) + * 3 -> 14 = 4 + 7(freeze TLV) + 3(users 1,2,3) + * 4 -> 16 = 4 + 7(freeze TLV) + 4(users 1,2,3,4) + 1(for 64-bit alignment) + * + * + * 2. CFR data size for max BW/Nss/Nrx + * + * Cypress : Max BW = 80 MHz + * NSS = 2 + * Nrx = 2 + * Size of one tone = 4 bytes + * + * a. RTT-H - 2048 bytes + * + * b. Debug-H (MIMO CFR) - 16016 bytes + * + * c. RTT-H + CIR - 10240 bytes = 2048(RTT-H) + 8192(CIR) + */ + +/* Max 4 users in MU case */ +#define CYP_CFR_MU_USERS 4 + +#define CYP_MAX_HEADER_LENGTH_WORDS 16 + +/* payload_len = Max(2048, 16016, 10240) = 16064 (64-bit alignment) */ +#define CYP_MAX_DATA_LENGTH_BYTES 16064 + +/* in ms */ +#define LUT_AGE_TIMER 3000 +#define LUT_AGE_THRESHOLD 3000 +#define NUM_LUT_ENTRIES 136 + +/* Max size : + * 16173 = 93 bytes(csi header) + 64 bytes(cfr header) + 16016 bytes(cfr + * payload) + */ +#define STREAMFS_MAX_SUBBUF_CYP 16173 + +#define STREAMFS_NUM_SUBBUF_CYP 255 + +/* + * @tag: ucode fills this with 0xBA + * + * @length: length of CFR header in words (32-bit) + * + * @upload_done: ucode sets this to 1 to indicate DMA completion + * + * @capture_type: + * + * 0 - None + * 1 - RTT-H (Nss = 1, Nrx) + * 2 - Debug-H (Nss, Nrx) + * 3 - Reserved + * 5 - RTT-H + CIR(Nss, Nrx) + * + * @preamble_type: + * + * 0 - Legacy + * 1 - HT + * 2 - VHT + * 3 - HE + * + * @nss: + * + * 0 - 1-stream + * 1 - 2-stream + * .. .. + * 7 - 8-stream + * + *@num_chains: + * + * 0 - 1-chain + * 1 - 2-chain + * .. .. + * 7 - 8-chain + * + *@upload_bw_pkt: + * + * 0 - 20 MHz + * 1 - 40 MHz + * 2 - 80 MHz + * 3 - 160 MHz + * + * @sw_peer_id_valid: Indicates whether sw_peer_id field is valid or not, + * sent from MAC to PHY via the MACRX_FREEZE_CAPTURE_CHANNEL TLV + * + * @sw_peer_id: Indicates peer id based on AST search, sent from MAC to PHY + * via the MACRX_FREEZE_CAPTURE_CHANNEL TLV + * + * @phy_ppdu_id: sent from PHY to MAC, copied to MACRX_FREEZE_CAPTURE_CHANNEL + * TLV + * + * @total_bytes: Total size of CFR payload (FFT bins) + * + * @header_version: + * + * 1 - HKV2/Hastings + * 2 - Cypress + * + * @target_id: + * + * 1 - Hastings + * 2 - Cypress + * 3 - Hastings Prime + * 4 - Pine + * + * @cfr_fmt: + * + * 0 - raw (32-bit format) + * 1 - compressed (24-bit format) + * + * @mu_rx_data_incl: Indicates whether CFR header contains UL-MU-MIMO info + * + * @freeze_data_incl: Indicates whether CFR header contains + * MACRX_FREEZE_CAPTURE_CHANNEL TLV + * + * @decimation_factor: FFT bins decimation + * @mu_rx_num_users: Number of users in UL-MU-PPDU + */ +struct whal_cfir_enhanced_hdr { + uint16_t tag : 8, + length : 6, + rsvd1 : 2; + + uint16_t upload_done : 1, + capture_type : 3, + preamble_type : 2, + nss : 3, + num_chains : 3, + upload_pkt_bw : 3, + sw_peer_id_valid : 1; + + uint16_t sw_peer_id : 16; + + uint16_t phy_ppdu_id : 16; + + uint16_t total_bytes; + + uint16_t header_version :4, + target_id :4, + cfr_fmt :1, + rsvd2 :1, + mu_rx_data_incl :1, + freeze_data_incl:1, + rsvd3 :4; + + uint16_t mu_rx_num_users :8, + decimation_factor :4, + rsvd4 :4; + + uint16_t rsvd5; +}; + +struct macrx_freeze_capture_channel { + uint16_t freeze : 1, //[0] + capture_reason : 3, //[3:1] + packet_type : 2, //[5:4] + packet_sub_type : 4, //[9:6] + reserved : 5, //[14:10] + sw_peer_id_valid : 1; //[15] + uint16_t sw_peer_id : 16; //[15:0] + uint16_t phy_ppdu_id : 16; //[15:0] + uint16_t packet_ta_lower_16 : 16; //[15:0] + uint16_t packet_ta_mid_16 : 16; //[15:0] + uint16_t packet_ta_upper_16 : 16; //[15:0] + uint16_t packet_ra_lower_16 : 16; //[15:0] + uint16_t packet_ra_mid_16 : 16; //[15:0] + uint16_t packet_ra_upper_16 : 16; //[15:0] + uint16_t tsf_timestamp_15_0 : 16; //[15:0] + uint16_t tsf_timestamp_31_16 : 16; //[15:0] + uint16_t tsf_timestamp_47_32 : 16; //[15:0] + uint16_t tsf_timestamp_63_48 : 16; //[15:0] + uint16_t user_index : 6, //[5:0] + directed : 1, //[6] + reserved_13 : 9; //[15:7] +}; + +struct uplink_user_setup_info { + uint32_t bw_info_valid : 1, //[0] + uplink_receive_type : 2, //[2:1] + reserved_0a : 1, //[3] + uplink_11ax_mcs : 4, //[7:4] + ru_width : 7, //[14:8] + reserved_0b : 1, //[15] + nss : 3, //[18:16] + stream_offset : 3, //[21:19] + sta_dcm : 1, //[22] + sta_coding : 1, //[23] + ru_start_index : 7, //[30:24] + reserved_0c : 1; //[31] +}; + +/** + * cfr_6018_init_pdev() - Inits cfr pdev and registers necessary handlers. + * @psoc: pointer to psoc object + * @pdev: pointer to pdev object + * + * Return: Registration status for necessary handlers + */ +QDF_STATUS cfr_6018_init_pdev( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev); + +/** + * cfr_6018_deinit_pdev() - De-inits corresponding pdev and handlers. + * @psoc: pointer to psoc object + * @pdev: pointer to pdev object + * + * Return: De-registration status for necessary handlers + */ +QDF_STATUS cfr_6018_deinit_pdev( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev); + +/** + * target_if_cfr_start_lut_age_timer() - Start timer to flush aged-out LUT + * entries + * @pdev: pointer to pdev object + * + * Return: None + */ +void target_if_cfr_start_lut_age_timer(struct wlan_objmgr_pdev *pdev); + +/** + * target_if_cfr_stop_lut_age_timer() - Stop timer to flush aged-out LUT + * entries + * @pdev: pointer to pdev object + * + * Return: None + */ +void target_if_cfr_stop_lut_age_timer(struct wlan_objmgr_pdev *pdev); + +/** + * target_if_cfr_dump_lut_enh() - Dump all valid LUT entries + * @pdev: objmgr PDEV + * + * Return: none + */ +void target_if_cfr_dump_lut_enh(struct wlan_objmgr_pdev *pdev); + +/** + * target_if_cfr_config_rcc() - Start repetitive channel capture + * @pdev: pointer to pdev object + * @rcc_param: rcc configurations + * + * Return: Success/Failure status + */ +QDF_STATUS target_if_cfr_config_rcc(struct wlan_objmgr_pdev *pdev, + struct cfr_rcc_param *rcc_param); + +/** + * target_if_cfr_default_ta_ra_config() - Configure default values to all + * params(BW/NSS/TA/RA) in TA_RA mode + * @rcc_param: rcc configurations + * @allvalid: Indicates whether all TA_RA params are valid or not. + * It could be either 0 or 1. + * 1: should be sent to FW during CFR initialization + * 0: should be set, after a successful commit session. + * @reset_cfg: This bitmap is being used to determine which groups' + * parameters are needed to be reset to its default state. + */ +void target_if_cfr_default_ta_ra_config(struct cfr_rcc_param *rcc_param, + bool allvalid, uint16_t reset_cfg); + +/** + * target_if_cfr_rx_tlv_process() - Process PPDU status TLVs and store info in + * lookup table + * @pdev: PDEV object + * @nbuf: ppdu info + * + * Return: none + */ +void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf); + +/** + * target_if_cfr_update_global_cfg() - Update global config after a successful + * commit + * @pdev: pointer to pdev object + * + * Return: None + */ +void target_if_cfr_update_global_cfg(struct wlan_objmgr_pdev *pdev); +#else +static QDF_STATUS cfr_6018_init_pdev( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS cfr_6018_deinit_pdev( + struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + return QDF_STATUS_SUCCESS; +} +#endif +#endif diff --git a/target_if/cfr/src/target_if_cfr.c b/target_if/cfr/src/target_if_cfr.c new file mode 100644 index 000000000000..dd216eb8c90f --- /dev/null +++ b/target_if/cfr/src/target_if_cfr.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int target_if_cfr_stop_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer) +{ + struct peer_cfr *pe; + struct peer_cfr_params param = {0}; + struct wmi_unified *pdev_wmi_handle = NULL; + struct wlan_objmgr_vdev *vdev = {0}; + struct pdev_cfr *pdev_cfrobj; + int retv = 0; + + pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR); + if (pe == NULL) + return -EINVAL; + + pdev_wmi_handle = lmac_get_pdev_wmi_handle(pdev); + vdev = wlan_peer_get_vdev(peer); + + qdf_mem_set(¶m, sizeof(param), 0); + + param.request = PEER_CFR_CAPTURE_DISABLE; + param.macaddr = wlan_peer_get_macaddr(peer); + param.vdev_id = wlan_vdev_get_id(vdev); + + param.periodicity = pe->period; + param.bandwidth = pe->bandwidth; + param.capture_method = pe->capture_method; + + retv = wmi_unified_send_peer_cfr_capture_cmd(pdev_wmi_handle, ¶m); + + pdev_cfrobj = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + if (!pdev_cfrobj) { + cfr_err("pdev object for CFR is null"); + return -EINVAL; + } + cfr_err("CFR capture stats for this capture:"); + cfr_err("DBR event count = %llu, Tx event count = %llu " + "Release count = %llu", + pdev_cfrobj->dbr_evt_cnt, pdev_cfrobj->tx_evt_cnt, + pdev_cfrobj->release_cnt); + + pdev_cfrobj->dbr_evt_cnt = 0; + pdev_cfrobj->tx_evt_cnt = 0; + pdev_cfrobj->release_cnt = 0; + + return retv; +} + +int target_if_cfr_start_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer, + struct cfr_capture_params *cfr_params) +{ + struct peer_cfr_params param = {0}; + struct wmi_unified *pdev_wmi_handle = NULL; + struct wlan_objmgr_vdev *vdev; + int retv = 0; + + pdev_wmi_handle = lmac_get_pdev_wmi_handle(pdev); + vdev = wlan_peer_get_vdev(peer); + qdf_mem_set(¶m, sizeof(param), 0); + + param.request = PEER_CFR_CAPTURE_ENABLE; + param.macaddr = wlan_peer_get_macaddr(peer); + param.vdev_id = wlan_vdev_get_id(vdev); + + param.periodicity = cfr_params->period; + param.bandwidth = cfr_params->bandwidth; + param.capture_method = cfr_params->method; + + retv = wmi_unified_send_peer_cfr_capture_cmd(pdev_wmi_handle, ¶m); + return retv; +} + +int target_if_cfr_pdev_set_param(struct wlan_objmgr_pdev *pdev, + uint32_t param_id, uint32_t param_value) +{ + struct pdev_params pparam; + uint32_t pdev_id; + + pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + if (pdev_id < 0) + return -EINVAL; + + qdf_mem_set(&pparam, sizeof(pparam), 0); + pparam.param_id = param_id; + pparam.param_value = param_value; + + return wmi_unified_pdev_param_send(lmac_get_pdev_wmi_handle(pdev), + &pparam, pdev_id); +} + +int target_if_cfr_enable_cfr_timer(struct wlan_objmgr_pdev *pdev, + uint32_t cfr_timer) +{ + struct pdev_cfr *pa; + int retval; + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + if (pa == NULL) + return QDF_STATUS_E_FAILURE; + + if (!cfr_timer) { + /* disable periodic cfr capture */ + retval = + target_if_cfr_pdev_set_param(pdev, + wmi_pdev_param_per_peer_prd_cfr_enable, + WMI_HOST_PEER_CFR_TIMER_DISABLE); + + if (retval == QDF_STATUS_SUCCESS) + pa->cfr_timer_enable = 0; + } else { + /* enable periodic cfr capture (default base timer is 10ms ) */ + retval = + target_if_cfr_pdev_set_param(pdev, + wmi_pdev_param_per_peer_prd_cfr_enable, + WMI_HOST_PEER_CFR_TIMER_ENABLE); + + if (retval == QDF_STATUS_SUCCESS) + pa->cfr_timer_enable = 1; + } + + return retval; +} + +int target_if_cfr_get_target_type(struct wlan_objmgr_psoc *psoc) +{ + uint32_t target_type = 0; + struct wlan_lmac_if_target_tx_ops *target_type_tx_ops; + + target_type_tx_ops = &psoc->soc_cb.tx_ops.target_tx_ops; + + if (target_type_tx_ops->tgt_get_tgt_type) + target_type = target_type_tx_ops->tgt_get_tgt_type(psoc); + + return target_type; +} + +int target_if_cfr_init_pdev(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + uint32_t target_type; + struct pdev_cfr *pa; + struct psoc_cfr *cfr_sc; + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + if (pa == NULL) + return QDF_STATUS_E_FAILURE; + + /* Reset unassociated entries for every init */ + qdf_mem_zero(&pa->unassoc_pool[0], MAX_CFR_ENABLED_CLIENTS * + sizeof(struct unassoc_pool_entry)); + + cfr_sc = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_CFR); + + if (cfr_sc == NULL) + return QDF_STATUS_E_FAILURE; + + target_type = target_if_cfr_get_target_type(psoc); + + if (target_type == TARGET_TYPE_QCA8074V2) { + pa->is_cfr_capable = cfr_sc->is_cfr_capable; + return cfr_8074v2_init_pdev(psoc, pdev); + } else if ((target_type == TARGET_TYPE_IPQ4019) || + (target_type == TARGET_TYPE_QCA9984) || + (target_type == TARGET_TYPE_QCA9888)) { + + pa->is_cfr_capable = cfr_sc->is_cfr_capable; + + return cfr_wifi2_0_init_pdev(psoc, pdev); + } else if (target_type == TARGET_TYPE_QCA6018) { + pa->is_cfr_capable = cfr_sc->is_cfr_capable; + return cfr_6018_init_pdev(psoc, pdev); + } else + return QDF_STATUS_E_NOSUPPORT; +} + +int target_if_cfr_deinit_pdev(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + uint32_t target_type; + + target_type = target_if_cfr_get_target_type(psoc); + + if (target_type == TARGET_TYPE_QCA8074V2) { + return cfr_8074v2_deinit_pdev(psoc, pdev); + } else if ((target_type == TARGET_TYPE_IPQ4019) || + (target_type == TARGET_TYPE_QCA9984) || + (target_type == TARGET_TYPE_QCA9888)) { + + return cfr_wifi2_0_deinit_pdev(psoc, pdev); + } else if (target_type == TARGET_TYPE_QCA6018) { + return cfr_6018_deinit_pdev(psoc, pdev); + } else + return QDF_STATUS_E_NOSUPPORT; +} + +#ifdef WLAN_ENH_CFR_ENABLE +QDF_STATUS target_if_cfr_config_rcc(struct wlan_objmgr_pdev *pdev, + struct cfr_rcc_param *rcc_info) +{ + QDF_STATUS status; + struct wmi_unified *pdev_wmi_handle = NULL; + + pdev_wmi_handle = lmac_get_pdev_wmi_handle(pdev); + if (!pdev_wmi_handle) { + cfr_err("pdev_wmi_handle is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + rcc_info->pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + rcc_info->num_grp_tlvs = + count_set_bits(rcc_info->modified_in_curr_session); + + status = wmi_unified_send_cfr_rcc_cmd(pdev_wmi_handle, rcc_info); + return status; +} + +void target_if_cfr_default_ta_ra_config(struct cfr_rcc_param *rcc_info, + bool allvalid, uint16_t reset_cfg) +{ + struct ta_ra_cfr_cfg *curr_cfg = NULL; + int grp_id; + + uint8_t def_mac[QDF_MAC_ADDR_SIZE] = {0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF}; + uint8_t null_mac[QDF_MAC_ADDR_SIZE] = {0, 0, 0, 0, 0, 0}; + + for (grp_id = 0; grp_id < MAX_TA_RA_ENTRIES; grp_id++) { + if (qdf_test_bit(grp_id, (unsigned long *)&reset_cfg)) { + curr_cfg = &rcc_info->curr[grp_id]; + qdf_mem_copy(curr_cfg->tx_addr, + def_mac, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(curr_cfg->tx_addr_mask, + null_mac, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(curr_cfg->rx_addr, + def_mac, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(curr_cfg->rx_addr_mask, + null_mac, QDF_MAC_ADDR_SIZE); + curr_cfg->bw = 0xf; + curr_cfg->nss = 0xff; + curr_cfg->mgmt_subtype_filter = 0xffff; + curr_cfg->ctrl_subtype_filter = 0xffff; + curr_cfg->data_subtype_filter = 0xffff; + if (!allvalid) { + curr_cfg->valid_ta = 0; + curr_cfg->valid_ta_mask = 0; + curr_cfg->valid_ra = 0; + curr_cfg->valid_ra_mask = 0; + curr_cfg->valid_bw_mask = 0; + curr_cfg->valid_nss_mask = 0; + curr_cfg->valid_mgmt_subtype = 0; + curr_cfg->valid_ctrl_subtype = 0; + curr_cfg->valid_data_subtype = 0; + } else { + curr_cfg->valid_ta = 1; + curr_cfg->valid_ta_mask = 1; + curr_cfg->valid_ra = 1; + curr_cfg->valid_ra_mask = 1; + curr_cfg->valid_bw_mask = 1; + curr_cfg->valid_nss_mask = 1; + curr_cfg->valid_mgmt_subtype = 1; + curr_cfg->valid_ctrl_subtype = 1; + curr_cfg->valid_data_subtype = 1; + } + } + } +} +#endif + +#ifdef WLAN_ENH_CFR_ENABLE +void target_if_enh_cfr_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ + tx_ops->cfr_tx_ops.cfr_config_rcc = + target_if_cfr_config_rcc; + tx_ops->cfr_tx_ops.cfr_start_lut_timer = + target_if_cfr_start_lut_age_timer; + tx_ops->cfr_tx_ops.cfr_stop_lut_timer = + target_if_cfr_stop_lut_age_timer; + tx_ops->cfr_tx_ops.cfr_default_ta_ra_cfg = + target_if_cfr_default_ta_ra_config; + tx_ops->cfr_tx_ops.cfr_dump_lut_enh = + target_if_cfr_dump_lut_enh; + tx_ops->cfr_tx_ops.cfr_rx_tlv_process = + target_if_cfr_rx_tlv_process; + tx_ops->cfr_tx_ops.cfr_update_global_cfg = + target_if_cfr_update_global_cfg; +} +#else +void target_if_enh_cfr_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ +} +#endif + +void target_if_cfr_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops) +{ + tx_ops->cfr_tx_ops.cfr_init_pdev = + target_if_cfr_init_pdev; + tx_ops->cfr_tx_ops.cfr_deinit_pdev = + target_if_cfr_deinit_pdev; + tx_ops->cfr_tx_ops.cfr_enable_cfr_timer = + target_if_cfr_enable_cfr_timer; + tx_ops->cfr_tx_ops.cfr_start_capture = + target_if_cfr_start_capture; + tx_ops->cfr_tx_ops.cfr_stop_capture = + target_if_cfr_stop_capture; + target_if_enh_cfr_tx_ops(tx_ops); +} + +void target_if_cfr_set_cfr_support(struct wlan_objmgr_psoc *psoc, + uint8_t value) +{ + if (psoc->soc_cb.rx_ops.cfr_rx_ops.cfr_support_set) + psoc->soc_cb.rx_ops.cfr_rx_ops.cfr_support_set(psoc, value); +} + +void target_if_cfr_info_send(struct wlan_objmgr_pdev *pdev, void *head, + size_t hlen, void *data, size_t dlen, void *tail, + size_t tlen) +{ + struct wlan_objmgr_psoc *psoc; + + psoc = wlan_pdev_get_psoc(pdev); + + if (psoc->soc_cb.rx_ops.cfr_rx_ops.cfr_info_send) + psoc->soc_cb.rx_ops.cfr_rx_ops.cfr_info_send(pdev, head, hlen, + data, dlen, tail, + tlen); +} diff --git a/target_if/cfr/src/target_if_cfr_6018.c b/target_if/cfr/src/target_if_cfr_6018.c new file mode 100644 index 000000000000..101810f0a464 --- /dev/null +++ b/target_if/cfr/src/target_if_cfr_6018.c @@ -0,0 +1,1618 @@ +/* + * Copyright (c) 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef DIRECT_BUF_RX_ENABLE +#include +#endif +#include +#include "cdp_txrx_ctrl.h" + +static u_int32_t end_magic = 0xBEAFDEAD; +/** + * get_lut_entry() - Retrieve LUT entry using cookie number + * @pcfr: PDEV CFR object + * @offset: cookie number + * + * Return: look up table entry + */ +static struct look_up_table *get_lut_entry(struct pdev_cfr *pcfr, + int offset) +{ + if (offset > NUM_LUT_ENTRIES) { + cfr_err("Invalid offset\n"); + return NULL; + } + return &pcfr->lut[offset]; +} + +/** + * release_lut_entry_enh() - Clear all params in an LUT entry + * @pdev: objmgr PDEV + * @lut: pointer to LUT + * + * Return: status + */ +int release_lut_entry_enh(struct wlan_objmgr_pdev *pdev, + struct look_up_table *lut) +{ + lut->dbr_recv = false; + lut->tx_recv = false; + lut->data = NULL; + lut->data_len = 0; + lut->dbr_ppdu_id = 0; + lut->tx_ppdu_id = 0; + lut->dbr_tstamp = 0; + lut->txrx_tstamp = 0; + lut->tx_address1 = 0; + lut->tx_address2 = 0; + lut->dbr_address = 0; + qdf_mem_zero(&lut->header, sizeof(struct csi_cfr_header)); + + return 0; +} + +/** + * target_if_cfr_dump_lut_enh() - dump all valid lut entries + * @pdev: objmgr pdev + * + * return: none + */ +void target_if_cfr_dump_lut_enh(struct wlan_objmgr_pdev *pdev) +{ + struct pdev_cfr *pcfr; + struct look_up_table *lut = NULL; + int i = 0; + uint64_t diff; + QDF_STATUS retval = 0; + + retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID); + if (retval != QDF_STATUS_SUCCESS) { + cfr_err("failed to get pdev reference"); + return; + } + + pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + if (!pcfr) { + cfr_err("pdev object for CFR is null"); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + return; + } + + for (i = 0; i < NUM_LUT_ENTRIES; i++) { + lut = get_lut_entry(pcfr, i); + if (!lut) + continue; + if (lut->dbr_recv ^ lut->tx_recv) { + diff = (lut->dbr_tstamp > lut->txrx_tstamp) ? + (lut->dbr_tstamp - lut->txrx_tstamp) : + (lut->txrx_tstamp - lut->dbr_tstamp); + cfr_err("idx:%d dbrevnt: %d txrxevent: %d " + "dbrppdu:0x%x txrxppdu:0x%x dbr_tstamp: %llu " + "txrx_tstamp: %llu diff: %llu\n", + i, lut->dbr_recv, lut->tx_recv, + lut->dbr_ppdu_id, lut->tx_ppdu_id, + lut->dbr_tstamp, lut->txrx_tstamp, diff); + } + + } + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); +} + +/** + * cfr_free_pending_dbr_events() - Flush all pending DBR events. This is useful + * in cases where for RXTLV drops in host monitor status ring is huge. + * @pdev: objmgr pdev + * + * return: none + */ +void cfr_free_pending_dbr_events(struct wlan_objmgr_pdev *pdev) +{ + struct pdev_cfr *pcfr; + struct look_up_table *lut = NULL; + int i = 0; + QDF_STATUS retval = 0; + + retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID); + if (retval != QDF_STATUS_SUCCESS) { + cfr_err("failed to get pdev reference"); + return; + } + + pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + if (!pcfr) { + cfr_err("pdev object for CFR is null"); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + return; + } + + for (i = 0; i < NUM_LUT_ENTRIES; i++) { + lut = get_lut_entry(pcfr, i); + if (!lut) + continue; + + if (lut->dbr_recv && !lut->tx_recv && + (lut->dbr_tstamp < pcfr->last_success_tstamp)) { + target_if_dbr_buf_release(pdev, DBR_MODULE_CFR, + lut->dbr_address, + i, 0); + pcfr->flush_dbr_cnt++; + release_lut_entry_enh(pdev, lut); + } + } + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); +} + +/** + * dump_freeze_tlv() - Dump freeze TLV sent in enhanced DMA header + * @freeze_tlv: Freeze TLV sent from MAC to PHY + * @cookie: Index into lookup table + * + * Return: none + */ +void dump_freeze_tlv(void *freeze_tlv, uint32_t cookie) +{ + struct macrx_freeze_capture_channel *freeze = + (struct macrx_freeze_capture_channel *)freeze_tlv; + + cfr_debug("<%u>\n" + "freeze: %d capture_reason: %d packet_type: 0x%x\n" + "packet_subtype: 0x%x sw_peer_id_valid: %d sw_peer_id: %d\n" + "phy_ppdu_id: 0x%04x packet_ta_upper_16: 0x%04x\n" + "packet_ta_mid_16: 0x%04x packet_ta_lower_16: 0x%04x\n" + "packet_ra_upper_16: 0x%04x packet_ra_mid_16: 0x%04x\n" + "packet_ra_lower_16: 0x%04x tsf_timestamp_63_48: 0x%04x\n" + "tsf_timestamp_47_32: 0x%04x tsf_timestamp_31_16: 0x%04x\n" + "tsf_timestamp_15_0: 0x%04x user_index: %d directed: %d\n", + cookie, + freeze->freeze, + freeze->capture_reason, + freeze->packet_type, + freeze->packet_sub_type, + freeze->sw_peer_id_valid, + freeze->sw_peer_id, + freeze->phy_ppdu_id, + freeze->packet_ta_upper_16, + freeze->packet_ta_mid_16, + freeze->packet_ta_lower_16, + freeze->packet_ra_upper_16, + freeze->packet_ra_mid_16, + freeze->packet_ra_lower_16, + freeze->tsf_timestamp_63_48, + freeze->tsf_timestamp_47_32, + freeze->tsf_timestamp_31_16, + freeze->tsf_timestamp_15_0, + freeze->user_index, + freeze->directed); +} + +/** + * dump_mu_rx_info() - Dump MU info in enhanced DMA header + * @mu_rx_user_info: MU info sent by ucode + * @mu_rx_num_users: Number of MU users in UL-MU-PPDU + * @cookie: Index into lookup table + * + * Return: none + */ +void dump_mu_rx_info(void *mu_rx_user_info, uint8_t mu_rx_num_users, + uint32_t cookie) +{ + uint8_t i; + struct uplink_user_setup_info *ul_mu_user_info = + (struct uplink_user_setup_info *) mu_rx_user_info; + + for (i = 0 ; i < mu_rx_num_users; i++) { + cfr_debug("<%u>\n" + "\n" + "bw_info_valid = %d\n" + "uplink_receive_type = %d\n" + "uplink_11ax_mcs = %d\n" + "ru_width = %d\n" + "nss = %d\n" + "stream_offset = %d\n" + "sta_dcm = %d\n" + "sta_coding = %d\n" + "ru_start_index = %d\n", + cookie, + i, + ul_mu_user_info->bw_info_valid, + ul_mu_user_info->uplink_receive_type, + ul_mu_user_info->uplink_11ax_mcs, + ul_mu_user_info->ru_width, + ul_mu_user_info->nss, + ul_mu_user_info->stream_offset, + ul_mu_user_info->sta_dcm, + ul_mu_user_info->sta_coding, + ul_mu_user_info->ru_start_index); + ul_mu_user_info += sizeof(struct uplink_user_setup_info); + } +} + +void dump_metadata(struct csi_cfr_header *header, uint32_t cookie) +{ + uint8_t user_id, chain_id; + struct cfr_metadata_version_3 *meta = &header->u.meta_v3; + uint8_t *usermac = NULL; + + cfr_debug("<%u>\n" + "start_magic_num = 0x%x\n" + "vendorid = 0x%x\n" + "cfr_metadata_version = %d\n" + "cfr_data_version = %d\n" + "chip_type = %d\n" + "platform_type = %d\n" + "status = %d\n" + "capture_bw = %d\n" + "channel_bw = %d\n" + "phy_mode = %d\n" + "prim20_chan = %d\n" + "center_freq1 = %d\n" + "center_freq2 = %d\n" + "ack_capture_mode = %d\n" + "cfr_capture_type = %d\n" + "sts_count = %d\n" + "num_rx_chain = %d\n" + "timestamp = 0x%x\n" + "length = %d\n" + "is_mu_ppdu = %d\n" + "num_users = %d\n", + cookie, + header->start_magic_num, + header->vendorid, + header->cfr_metadata_version, + header->cfr_data_version, + header->chip_type, + header->pltform_type, + meta->status, + meta->capture_bw, + meta->channel_bw, + meta->phy_mode, + meta->prim20_chan, + meta->center_freq1, + meta->center_freq2, + meta->capture_mode, + meta->capture_type, + meta->sts_count, + meta->num_rx_chain, + meta->timestamp, + meta->length, + meta->is_mu_ppdu, + meta->num_mu_users); + + if (meta->is_mu_ppdu) { + for (user_id = 0; user_id < meta->num_mu_users; user_id++) { + usermac = meta->peer_addr.mu_peer_addr[user_id]; + cfr_debug("peermac[%d]: %s\n", + user_id, + ether_sprintf(usermac)); + } + } else { + cfr_debug("peermac: %s\n", + ether_sprintf(meta->peer_addr.su_peer_addr)); + } + + for (chain_id = 0; chain_id < HOST_MAX_CHAINS; chain_id++) { + cfr_debug("chain_rssi[%d] = %d\n", + chain_id, + meta->chain_rssi[chain_id]); + } + + for (chain_id = 0; chain_id < HOST_MAX_CHAINS; chain_id++) { + cfr_debug("chain_phase[%d] = %d\n", + chain_id, + meta->chain_phase[chain_id]); + } +} +/** + * dump_enh_dma_hdr() - Dump enhanced DMA header populated by ucode + * @dma_hdr: pointer to enhanced DMA header + * @freeze_tlv: pointer to MACRX_FREEZE_CAPTURE_CHANNEL TLV + * @mu_rx_user_info: UPLINK_USER_SETUP_INFO TLV + * @header: pointer to metadata passed to userspace + * @error: Indicates whether it is an error + * @cookie: Index into lookup table + * + * Return: none + */ +void dump_enh_dma_hdr(struct whal_cfir_enhanced_hdr *dma_hdr, + void *freeze_tlv, + void *mu_rx_user_info, + struct csi_cfr_header *header, + int error, + uint32_t cookie) +{ + if (!error) { + cfr_debug("<%u>\n" + "Tag: 0x%02x Length: %d udone: %d\n" + "ctype: %d preamble: %d Nss: %d\n" + "num_chains: %d bw: %d peervalid: %d\n" + "peer_id: %d ppdu_id: 0x%04x total_bytes: %d\n" + "header_version: %d target_id: %d cfr_fmt: %d\n" + "mu_rx_data_incl: %d freeze_data_incl: %d\n" + "mu_rx_num_users: %d decimation_factor: %d\n", + cookie, + dma_hdr->tag, + dma_hdr->length, + dma_hdr->upload_done, + dma_hdr->capture_type, + dma_hdr->preamble_type, + dma_hdr->nss, + dma_hdr->num_chains, + dma_hdr->upload_pkt_bw, + dma_hdr->sw_peer_id_valid, + dma_hdr->sw_peer_id, + dma_hdr->phy_ppdu_id, + dma_hdr->total_bytes, + dma_hdr->header_version, + dma_hdr->target_id, + dma_hdr->cfr_fmt, + dma_hdr->mu_rx_data_incl, + dma_hdr->freeze_data_incl, + dma_hdr->mu_rx_num_users, + dma_hdr->decimation_factor); + + if (dma_hdr->freeze_data_incl) + dump_freeze_tlv(freeze_tlv, cookie); + + if (dma_hdr->mu_rx_data_incl) + dump_mu_rx_info(mu_rx_user_info, + dma_hdr->mu_rx_num_users, + cookie); + } else { + cfr_err("<%u>\n" + "Tag: 0x%02x Length: %d udone: %d\n" + "ctype: %d preamble: %d Nss: %d\n" + "num_chains: %d bw: %d peervalid: %d\n" + "peer_id: %d ppdu_id: 0x%04x total_bytes: %d\n" + "header_version: %d target_id: %d cfr_fmt: %d\n" + "mu_rx_data_incl: %d freeze_data_incl: %d\n" + "mu_rx_num_users: %d decimation_factor: %d\n", + cookie, + dma_hdr->tag, + dma_hdr->length, + dma_hdr->upload_done, + dma_hdr->capture_type, + dma_hdr->preamble_type, + dma_hdr->nss, + dma_hdr->num_chains, + dma_hdr->upload_pkt_bw, + dma_hdr->sw_peer_id_valid, + dma_hdr->sw_peer_id, + dma_hdr->phy_ppdu_id, + dma_hdr->total_bytes, + dma_hdr->header_version, + dma_hdr->target_id, + dma_hdr->cfr_fmt, + dma_hdr->mu_rx_data_incl, + dma_hdr->freeze_data_incl, + dma_hdr->mu_rx_num_users, + dma_hdr->decimation_factor); + } +} + + +/** + * extract_peer_mac_from_freeze_tlv() - extract macaddr from freeze tlv + * @freeze_tlv: Freeze TLV sent from MAC to PHY + * @peermac: macaddr of the peer + * + * Return: none + */ +void extract_peer_mac_from_freeze_tlv(void *freeze_tlv, uint8_t *peermac) +{ + struct macrx_freeze_capture_channel *freeze = + (struct macrx_freeze_capture_channel *)freeze_tlv; + + peermac[0] = freeze->packet_ta_lower_16 & 0x00FF; + peermac[1] = (freeze->packet_ta_lower_16 & 0xFF00) >> 8; + peermac[2] = freeze->packet_ta_mid_16 & 0x00FF; + peermac[3] = (freeze->packet_ta_mid_16 & 0xFF00) >> 8; + peermac[4] = freeze->packet_ta_upper_16 & 0x00FF; + peermac[5] = (freeze->packet_ta_upper_16 & 0xFF00) >> 8; +} + +/** + * check_dma_length() - Sanity check DMA header and payload length + * @dma_hdr: pointer to enhanced DMA header + * + * Return: QDF_STATUS + */ +QDF_STATUS check_dma_length(struct look_up_table *lut) +{ + if (lut->header_length <= CYP_MAX_HEADER_LENGTH_WORDS && + lut->payload_length <= CYP_MAX_DATA_LENGTH_BYTES) { + return QDF_STATUS_SUCCESS; + } else { + return QDF_STATUS_E_FAILURE; + } +} + +/** + * correlate_and_relay_enh() - Correlate TXRX and DBR events and stream CFR + * data to userspace + * @pdev: objmgr PDEV + * @cookie: Index into lookup table + * @lut: pointer to lookup table + * @module_id: ID of the event received + * 0 - DBR event + * 1 - TXRX event + * + * Return: + * - STATUS_ERROR + * - STATUS_HOLD + * - STATUS_STREAM_AND_RELEASE + */ +int correlate_and_relay_enh(struct wlan_objmgr_pdev *pdev, uint32_t cookie, + struct look_up_table *lut, uint8_t module_id) +{ + struct pdev_cfr *pcfr; + uint64_t diff; + int status = STATUS_ERROR; + + if (module_id > 1) { + cfr_err("Received request with invalid mod id. Investigate!!"); + QDF_ASSERT(0); + status = STATUS_ERROR; + goto done; + } + + + pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + + if (module_id == CORRELATE_TX_EV_MODULE_ID) { + if (lut->tx_recv) + pcfr->cfr_dma_aborts++; + lut->tx_recv = true; + } else if (module_id == CORRELATE_DBR_MODULE_ID) { + pcfr->dbr_evt_cnt++; + lut->dbr_recv = true; + } + + if ((lut->dbr_recv == true) && (lut->tx_recv == true)) { + if (lut->dbr_ppdu_id == lut->tx_ppdu_id) { + + pcfr->last_success_tstamp = lut->dbr_tstamp; + if (lut->dbr_tstamp > lut->txrx_tstamp) { + diff = lut->dbr_tstamp - lut->txrx_tstamp; + cfr_debug("<%u>: " + "TXRX evt -> DBR evt" + "(delay = %llu ms)\n", cookie, diff); + } else if (lut->txrx_tstamp > lut->dbr_tstamp) { + diff = lut->txrx_tstamp - lut->dbr_tstamp; + cfr_debug("<%u>: " + "DBR evt -> TXRX evt" + "(delay = %llu ms)\n", cookie, diff); + } + + /* + * Flush pending dbr events, if newer PPDU TLV is + * received + */ + cfr_free_pending_dbr_events(pdev); + + if (check_dma_length(lut) == QDF_STATUS_SUCCESS) { + pcfr->release_cnt++; + cfr_debug("<%u>:Stream and release " + "CFR data for " + "ppdu_id:0x%04x\n", cookie, + lut->tx_ppdu_id); + status = STATUS_STREAM_AND_RELEASE; + goto done; + } else { + pcfr->invalid_dma_length_cnt++; + cfr_err("<%u>:CFR buffers " + "received with invalid length " + "header_length_words = %d " + "cfr_payload_length_bytes = %d " + "ppdu_id:0x%04x\n", + cookie, + lut->header_length, + lut->payload_length, + lut->tx_ppdu_id); + /* + * Assert here as length exceeding the allowed + * limit would anyway manifest as random crash + */ + QDF_ASSERT(0); + status = STATUS_ERROR; + goto done; + } + } else { + /* + * When there is a ppdu id mismatch, discard the TXRX + * event since multiple PPDUs are likely to have same + * dma addr, due to ucode aborts + */ + cfr_debug("Received new dbr event for same " + "cookie %u", + cookie); + lut->tx_recv = false; + lut->tx_ppdu_id = 0; + pcfr->clear_txrx_event++; + pcfr->cfr_dma_aborts++; + status = STATUS_HOLD; + } + } else { + status = STATUS_HOLD; + } +done: + return status; +} + +/** + * target_if_cfr_rx_tlv_process() - Process PPDU status TLVs and store info in + * lookup table + * @pdev_obj: PDEV object + * @nbuf: ppdu info + * + * Return: none + */ +void target_if_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf) +{ + struct cdp_rx_indication_ppdu *cdp_rx_ppdu; + struct cdp_rx_stats_ppdu_user *rx_stats_peruser; + struct cdp_rx_ppdu_cfr_info *cfr_info; + qdf_dma_addr_t buf_addr = 0, buf_addr_extn = 0; + struct pdev_cfr *pcfr; + struct look_up_table *lut = NULL; + struct csi_cfr_header *header = NULL; + uint32_t cookie; + struct wlan_objmgr_psoc *psoc; + struct wlan_channel *bss_chan; + enum wlan_phymode ch_phymode; + uint16_t ch_freq; + uint32_t ch_cfreq1; + uint32_t ch_cfreq2; + uint8_t rx_chainmask; + struct wlan_objmgr_vdev *vdev = NULL; + int i, status = 0; + QDF_STATUS retval = 0; + struct wlan_lmac_if_cfr_rx_ops *cfr_rx_ops = NULL; + struct cfr_metadata_version_3 *meta = NULL; + + if (qdf_unlikely(!pdev)) { + cfr_err("pdev is null\n"); + qdf_nbuf_free(nbuf); + return; + } + + retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID); + if (qdf_unlikely(retval != QDF_STATUS_SUCCESS)) { + cfr_err("failed to get pdev reference"); + qdf_nbuf_free(nbuf); + return; + } + + pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + if (qdf_unlikely(!pcfr)) { + cfr_err("pdev object for CFR is NULL"); + goto done; + } + + cdp_rx_ppdu = (struct cdp_rx_indication_ppdu *)qdf_nbuf_data(nbuf); + cfr_info = &cdp_rx_ppdu->cfr_info; + + if (!cfr_info->bb_captured_channel) + goto done; + + psoc = wlan_pdev_get_psoc(pdev); + if (qdf_unlikely(!psoc)) { + cfr_err("psoc is null\n"); + goto done; + } + + cfr_rx_ops = &psoc->soc_cb.rx_ops.cfr_rx_ops; + buf_addr_extn = cfr_info->rtt_che_buffer_pointer_high8 & 0xF; + buf_addr = (cfr_info->rtt_che_buffer_pointer_low32 | + ((uint64_t)buf_addr_extn << 32)); + + + if (target_if_dbr_cookie_lookup(pdev, DBR_MODULE_CFR, buf_addr, + &cookie, 0)) { + cfr_debug("Cookie lookup failure for addr: 0x%pK", + (void *)((uintptr_t)buf_addr)); + goto done; + } + + cfr_debug("<%u>:buffer address: 0x%pK \n" + " ppdu_id: 0x%04x\n" + " BB_CAPTURED_CHANNEL = %d\n" + " RX_LOCATION_INFO_VALID = %d\n" + " RTT_CHE_BUFFER_POINTER_LOW32 = %x\n" + " RTT_CHE_BUFFER_POINTER_HIGH8 = %x\n" + " CHAN_CAPTURE_STATUS = %d\n", + cookie, + (void *)((uintptr_t)buf_addr), + cdp_rx_ppdu->ppdu_id, + cfr_info->bb_captured_channel, + cfr_info->rx_location_info_valid, + cfr_info->rtt_che_buffer_pointer_low32, + cfr_info->rtt_che_buffer_pointer_high8, + cfr_info->chan_capture_status); + + lut = get_lut_entry(pcfr, cookie); + if (qdf_unlikely(!lut)) { + cfr_err("lut is NULL"); + goto done; + } + + vdev = wlan_objmgr_pdev_get_first_vdev(pdev, WLAN_CFR_ID); + if (qdf_unlikely(!vdev)) { + cfr_debug("vdev is null\n"); + goto done; + } + + bss_chan = wlan_vdev_mlme_get_bss_chan(vdev); + ch_freq = bss_chan->ch_freq; + ch_cfreq1 = bss_chan->ch_cfreq1; + ch_cfreq2 = bss_chan->ch_cfreq2; + ch_phymode = bss_chan->ch_phymode; + rx_chainmask = wlan_vdev_mlme_get_rxchainmask(vdev); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID); + + pcfr->rx_tlv_evt_cnt++; + lut->tx_ppdu_id = cdp_rx_ppdu->ppdu_id; + lut->tx_address1 = cfr_info->rtt_che_buffer_pointer_low32; + lut->tx_address2 = cfr_info->rtt_che_buffer_pointer_high8; + lut->txrx_tstamp = qdf_ktime_to_ms(qdf_ktime_get()); + header = &lut->header; + meta = &header->u.meta_v3; + + header->start_magic_num = 0xDEADBEAF; + header->vendorid = 0x8cfdf0; + header->cfr_metadata_version = CFR_META_VERSION_3; + header->cfr_data_version = CFR_DATA_VERSION_1; + header->chip_type = CFR_CAPTURE_RADIO_CYP; + header->pltform_type = CFR_PLATFORM_TYPE_ARM; + header->Reserved = 0; + + meta->status = 1; + meta->capture_bw = cdp_rx_ppdu->u.bw; + meta->phy_mode = ch_phymode; + meta->prim20_chan = ch_freq; + meta->center_freq1 = ch_cfreq1; + meta->center_freq2 = ch_cfreq2; + meta->capture_mode = 0; + meta->num_rx_chain = rx_chainmask; + + meta->timestamp = cdp_rx_ppdu->timestamp; + meta->is_mu_ppdu = (cdp_rx_ppdu->u.ppdu_type == CDP_RX_TYPE_SU) ? 0 : 1; + meta->num_mu_users = (meta->is_mu_ppdu) ? (cdp_rx_ppdu->num_users) : 0; + + if (meta->num_mu_users > CYP_CFR_MU_USERS) + meta->num_mu_users = CYP_CFR_MU_USERS; + + for (i = 0; i < MAX_CHAIN; i++) + meta->chain_rssi[i] = cdp_rx_ppdu->per_chain_rssi[i]; + + if (cdp_rx_ppdu->u.ppdu_type == CDP_RX_TYPE_SU) { + qdf_mem_copy(meta->peer_addr.su_peer_addr, + cdp_rx_ppdu->mac_addr, + QDF_MAC_ADDR_SIZE); + } else { + for (i = 0 ; i < meta->num_mu_users; i++) { + rx_stats_peruser = &cdp_rx_ppdu->user[i]; + qdf_mem_copy(meta->peer_addr.mu_peer_addr[i], + rx_stats_peruser->mac_addr, + QDF_MAC_ADDR_SIZE); + } + } + status = correlate_and_relay_enh(pdev, cookie, lut, + CORRELATE_TX_EV_MODULE_ID); + if (status == STATUS_STREAM_AND_RELEASE) { + if (cfr_rx_ops->cfr_info_send) + status = cfr_rx_ops->cfr_info_send(pdev, + &lut->header, + sizeof(struct + csi_cfr_header), + lut->data, + lut->data_len, + &end_magic, 4); + dump_metadata(header, cookie); + release_lut_entry_enh(pdev, lut); + target_if_dbr_buf_release(pdev, DBR_MODULE_CFR, buf_addr, + cookie, 0); + cfr_debug("Data sent to upper layers, release look up table"); + } else if (status == STATUS_HOLD) { + cfr_debug("HOLD for buffer address: 0x%pK cookie: %u", + (void *)((uintptr_t)buf_addr), cookie); + } else { + cfr_err("Correlation returned invalid status!!"); + } +done: + qdf_nbuf_free(nbuf); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); +} + +/** + * freeze_reason_to_capture_type() - Convert capture type enum in freeze tlv + * to the cfr type enum shared with userspace + * @freeze_tlv: pointer to MACRX_FREEZE_CAPTURE_CHANNEL TLV + * + * Return: cfr type enum + */ +uint8_t freeze_reason_to_capture_type(void *freeze_tlv) +{ + struct macrx_freeze_capture_channel *freeze = + (struct macrx_freeze_capture_channel *)freeze_tlv; + + switch (freeze->capture_reason) { + case FREEZE_REASON_TM: + return CFR_TYPE_METHOD_TM; + case FREEZE_REASON_FTM: + return CFR_TYPE_METHOD_FTM; + case FREEZE_REASON_TA_RA_TYPE_FILTER: + return CFR_TYPE_METHOD_TA_RA_TYPE_FILTER; + case FREEZE_REASON_NDPA_NDP: + return CFR_TYPE_METHOD_NDPA_NDP; + case FREEZE_REASON_ALL_PACKET: + return CFR_TYPE_METHOD_ALL_PACKET; + case FREEZE_REASON_ACK_RESP_TO_TM_FTM: + return CFR_TYPE_METHOD_ACK_RESP_TO_TM_FTM; + default: + return CFR_TYPE_METHOD_AUTO; + } + return CFR_TYPE_METHOD_AUTO; +} + +#ifdef DIRECT_BUF_RX_ENABLE +/** + * enh_cfr_dbr_event_handler() - Process DBR event for CFR data DMA completion + * @pdev: PDEV object + * @payload: pointer to CFR data + * + * Return: status + */ +bool enh_cfr_dbr_event_handler(struct wlan_objmgr_pdev *pdev, + struct direct_buf_rx_data *payload) +{ + uint8_t *data = NULL; + uint32_t cookie = 0; + struct whal_cfir_enhanced_hdr dma_hdr = {0}; + int length, status = 0; + struct wlan_objmgr_psoc *psoc; + struct pdev_cfr *pcfr; + struct look_up_table *lut = NULL; + struct csi_cfr_header *header = NULL; + void *mu_rx_user_info = NULL, *freeze_tlv = NULL; + uint8_t capture_type; + uint8_t *peer_macaddr = NULL; + struct wlan_lmac_if_cfr_rx_ops *cfr_rx_ops = NULL; + struct cfr_metadata_version_3 *meta = NULL; + + if ((!pdev) || (!payload)) { + cfr_err("pdev or payload is null"); + return true; + } + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + cfr_err("psoc is null"); + return true; + } + + cfr_rx_ops = &psoc->soc_cb.rx_ops.cfr_rx_ops; + + pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + if (!pcfr) { + cfr_err("pdev object for CFR is null"); + return true; + } + + data = payload->vaddr; + cookie = payload->cookie; + + cfr_debug("<%u>:bufferaddr: 0x%pK cookie: %u\n", cookie, + (void *)((uintptr_t)payload->paddr), cookie); + + qdf_mem_copy(&dma_hdr, &data[0], + sizeof(struct whal_cfir_enhanced_hdr)); + + if (dma_hdr.freeze_data_incl) { + freeze_tlv = data + sizeof(struct whal_cfir_enhanced_hdr); + capture_type = freeze_reason_to_capture_type(freeze_tlv); + } + + if (dma_hdr.mu_rx_data_incl) { + mu_rx_user_info = data + + sizeof(struct whal_cfir_enhanced_hdr) + + (dma_hdr.freeze_data_incl ? + sizeof(struct macrx_freeze_capture_channel) : 0); + } + + + length = dma_hdr.length * 4; + length += dma_hdr.total_bytes; /* size of cfr data */ + + lut = get_lut_entry(pcfr, cookie); + if (!lut) { + cfr_err("lut is NULL"); + return true; + } + + lut->data = data; + lut->data_len = length; + lut->dbr_ppdu_id = dma_hdr.phy_ppdu_id; + lut->dbr_address = payload->paddr; + lut->dbr_tstamp = qdf_ktime_to_ms(qdf_ktime_get()); + lut->header_length = dma_hdr.length; + lut->payload_length = dma_hdr.total_bytes; + qdf_mem_copy(&lut->dma_hdr, &dma_hdr, + sizeof(struct whal_cfir_dma_hdr)); + + header = &lut->header; + meta = &header->u.meta_v3; + meta->channel_bw = dma_hdr.upload_pkt_bw; + meta->length = length; + /* For Tx based captures, capture type is sent from FW */ + if (capture_type != CFR_TYPE_METHOD_ACK_RESP_TO_TM_FTM) { + meta->capture_type = capture_type; + meta->sts_count = (dma_hdr.nss + 1); + if (!dma_hdr.mu_rx_data_incl) { + /* extract peer addr from freeze tlv */ + peer_macaddr = + meta->peer_addr.su_peer_addr; + extract_peer_mac_from_freeze_tlv(freeze_tlv, + peer_macaddr); + } + } + + dump_enh_dma_hdr(&dma_hdr, freeze_tlv, mu_rx_user_info, + header, 0, cookie); + status = correlate_and_relay_enh(pdev, cookie, lut, + CORRELATE_DBR_MODULE_ID); + if (status == STATUS_STREAM_AND_RELEASE) { + /* + * Message format + * Meta data Header + actual payload + trailer + */ + if (cfr_rx_ops->cfr_info_send) + status = cfr_rx_ops->cfr_info_send(pdev, + &lut->header, + sizeof(struct + csi_cfr_header), + lut->data, + lut->data_len, + &end_magic, 4); + dump_metadata(header, cookie); + release_lut_entry_enh(pdev, lut); + cfr_debug("Data sent to upper layers, released look up table"); + status = true; + } else if (status == STATUS_HOLD) { + cfr_debug("TxRx event not received yet. " + "Buffer is not released"); + status = false; + } else { + cfr_err("Correlation returned invalid status!!"); + status = true; + } + + return status; +} + +/** + * target_if_register_to_dbr_enh() - Initialize DBR ring and register callback + * for DBR events + * @pdev: PDEV object + * + * Return: status + */ +QDF_STATUS +target_if_register_to_dbr_enh(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_lmac_if_direct_buf_rx_tx_ops *dbr_tx_ops = NULL; + struct dbr_module_config dbr_config; + + psoc = wlan_pdev_get_psoc(pdev); + dbr_tx_ops = &psoc->soc_cb.tx_ops.dbr_tx_ops; + dbr_config.num_resp_per_event = DBR_NUM_RESP_PER_EVENT_CFR; + dbr_config.event_timeout_in_ms = DBR_EVENT_TIMEOUT_IN_MS_CFR; + if (dbr_tx_ops->direct_buf_rx_module_register) { + return dbr_tx_ops->direct_buf_rx_module_register + (pdev, DBR_MODULE_CFR, &dbr_config, + enh_cfr_dbr_event_handler); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_unregister_to_dbr_enh() - Unregister callback for DBR events + * @pdev: PDEV object + * + * Return: status + */ +QDF_STATUS +target_if_unregister_to_dbr_enh(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_objmgr_psoc *psoc; + struct wlan_lmac_if_direct_buf_rx_tx_ops *dbr_tx_ops = NULL; + + psoc = wlan_pdev_get_psoc(pdev); + dbr_tx_ops = &psoc->soc_cb.tx_ops.dbr_tx_ops; + if (dbr_tx_ops->direct_buf_rx_module_unregister) { + return dbr_tx_ops->direct_buf_rx_module_unregister + (pdev, DBR_MODULE_CFR); + } + + return QDF_STATUS_SUCCESS; +} +#endif + +/** + * dump_cfr_peer_tx_event_enh() - Dump TX completion event + * @event: ptr to WMI TX completion event for QOS frames sent during + * one-shot capture + * @cookie: Index into lookup table + * + * Return: none + */ +void dump_cfr_peer_tx_event_enh(wmi_cfr_peer_tx_event_param *event, + uint32_t cookie) +{ + cfr_debug("<%u>CFR capture method: %d vdev_id: %d mac: %s\n", + cookie, + event->capture_method, event->vdev_id, + ether_sprintf(&event->peer_mac_addr.bytes[0])); + + cfr_debug("<%u>Chan: %d bw: %d phymode: %d cfreq1: %d cfrq2: %d " + "nss: %d\n", + cookie, + event->primary_20mhz_chan, event->bandwidth, + event->phy_mode, event->band_center_freq1, + event->band_center_freq2, event->spatial_streams); + + cfr_debug("<%u>Correlation_info1: 0x%08x " + "Correlation_info2: 0x%08x\n", + cookie, + event->correlation_info_1, event->correlation_info_2); + + cfr_debug("<%u>status: 0x%x ts: %d counter: %d rssi0: 0x%08x\n", + cookie, + event->status, event->timestamp_us, event->counter, + event->chain_rssi[0]); +} + +#ifdef DIRECT_BUF_RX_ENABLE +/** + * enh_prepare_cfr_header_txstatus() - Prepare CFR metadata for TX failures + * @tx_evt_param: ptr to WMI TX completion event + * @header: pointer to metadata + * + * Return: none + */ +static void enh_prepare_cfr_header_txstatus(wmi_cfr_peer_tx_event_param + *tx_evt_param, + struct csi_cfr_header *header) +{ + header->start_magic_num = 0xDEADBEAF; + header->vendorid = 0x8cfdf0; + header->cfr_metadata_version = CFR_META_VERSION_3; + header->cfr_data_version = CFR_DATA_VERSION_1; + header->chip_type = CFR_CAPTURE_RADIO_CYP; + header->pltform_type = CFR_PLATFORM_TYPE_ARM; + header->Reserved = 0; + header->u.meta_v3.status = 0; /* failure */ + header->u.meta_v3.length = 0; + + qdf_mem_copy(&header->u.meta_v2.peer_addr[0], + &tx_evt_param->peer_mac_addr.bytes[0], QDF_MAC_ADDR_SIZE); + +} + +/** + * target_if_peer_capture_event() - WMI TX completion event for one-shot + * capture + * @sc: pointer to offload soc object + * @data: WMI TX completion event buffer + * @datalen: WMI Tx completion event buffer length + * + * Return: status + */ +static int +target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen) +{ + QDF_STATUS retval = 0; + ol_ath_soc_softc_t *scn = (ol_ath_soc_softc_t *)sc; + struct wmi_unified *wmi_handle; + struct wlan_objmgr_psoc *psoc; + struct wlan_objmgr_pdev *pdev; + struct wlan_objmgr_vdev *vdev; + uint32_t cookie; + struct pdev_cfr *pcfr; + struct look_up_table *lut = NULL; + struct csi_cfr_header *header = NULL; + struct csi_cfr_header header_error = {0}; + wmi_cfr_peer_tx_event_param tx_evt_param = {0}; + qdf_dma_addr_t buf_addr = 0, buf_addr_temp = 0; + int status; + struct wlan_channel *bss_chan; + struct wlan_lmac_if_cfr_rx_ops *cfr_rx_ops = NULL; + + psoc = scn->psoc_obj; + if (!psoc) { + cfr_err("psoc is null"); + return -EINVAL; + } + + cfr_rx_ops = &psoc->soc_cb.rx_ops.cfr_rx_ops; + + retval = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_CFR_ID); + if (QDF_IS_STATUS_ERROR(retval)) { + cfr_err("unable to get psoc reference"); + return -EINVAL; + } + + wmi_handle = GET_WMI_HDL_FROM_PSOC(psoc); + if (!wmi_handle) { + cfr_err("wmi_handle is null"); + wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); + return -EINVAL; + } + + + retval = wmi_extract_cfr_peer_tx_event_param(wmi_handle, data, + &tx_evt_param); + + if (retval != QDF_STATUS_SUCCESS) { + cfr_err("Failed to extract cfr tx event param"); + wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); + return -EINVAL; + } + + + vdev = wlan_objmgr_get_vdev_by_id_from_psoc(psoc, tx_evt_param.vdev_id, + WLAN_CFR_ID); + if (!vdev) { + cfr_err("vdev is null"); + wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); + return -EINVAL; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + cfr_err("pdev is null"); + wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID); + return -EINVAL; + } + + retval = wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID); + if (retval != QDF_STATUS_SUCCESS) { + cfr_err("failed to get pdev reference"); + wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID); + return -EINVAL; + } + + pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + if (!pcfr) { + cfr_err("pdev object for CFR is NULL"); + retval = -EINVAL; + goto end; + } + + if ((tx_evt_param.status & PEER_CFR_CAPTURE_EVT_PS_STATUS_MASK) == 1) { + cfr_err("CFR capture failed as peer is in powersave : %s", + ether_sprintf(&tx_evt_param.peer_mac_addr.bytes[0])); + + enh_prepare_cfr_header_txstatus(&tx_evt_param, &header_error); + if (cfr_rx_ops->cfr_info_send) + cfr_rx_ops->cfr_info_send(pdev, + &header_error, + sizeof(struct + csi_cfr_header), + NULL, 0, &end_magic, 4); + + retval = -EINVAL; + goto end; + } + + if ((tx_evt_param.status & PEER_CFR_CAPTURE_EVT_STATUS_MASK) == 0) { + cfr_debug("CFR capture failed for peer : %s", + ether_sprintf(&tx_evt_param.peer_mac_addr.bytes[0])); + retval = -EINVAL; + goto end; + } + + if (tx_evt_param.status & CFR_TX_EVT_STATUS_MASK) { + cfr_debug("TX packet returned status %d for peer: %s", + tx_evt_param.status & CFR_TX_EVT_STATUS_MASK, + ether_sprintf(&tx_evt_param.peer_mac_addr.bytes[0])); + retval = -EINVAL; + goto end; + } + + buf_addr_temp = (tx_evt_param.correlation_info_2 & 0x0f); + buf_addr = (tx_evt_param.correlation_info_1 | + ((uint64_t)buf_addr_temp << 32)); + + if (target_if_dbr_cookie_lookup(pdev, DBR_MODULE_CFR, buf_addr, + &cookie, 0)) { + cfr_debug("Cookie lookup failure for addr: 0x%pK status: 0x%x", + (void *)((uintptr_t)buf_addr), tx_evt_param.status); + retval = -EINVAL; + goto end; + } + + cfr_debug("buffer address: 0x%pK cookie: %u", + (void *)((uintptr_t)buf_addr), cookie); + + dump_cfr_peer_tx_event_enh(&tx_evt_param, cookie); + + lut = get_lut_entry(pcfr, cookie); + if (!lut) { + cfr_err("lut is NULL\n"); + retval = -EINVAL; + goto end; + } + + pcfr->tx_evt_cnt++; + pcfr->total_tx_evt_cnt++; + + lut->tx_ppdu_id = (tx_evt_param.correlation_info_2 >> 16); + lut->tx_address1 = tx_evt_param.correlation_info_1; + lut->tx_address2 = tx_evt_param.correlation_info_2; + lut->txrx_tstamp = qdf_ktime_to_ms(qdf_ktime_get()); + + header = &lut->header; + header->start_magic_num = 0xDEADBEAF; + header->vendorid = 0x8cfdf0; + header->cfr_metadata_version = CFR_META_VERSION_3; + header->cfr_data_version = CFR_DATA_VERSION_1; + header->chip_type = CFR_CAPTURE_RADIO_CYP; + header->pltform_type = CFR_PLATFORM_TYPE_ARM; + header->Reserved = 0; + header->u.meta_v3.status = (tx_evt_param.status & + PEER_CFR_CAPTURE_EVT_STATUS_MASK) ? + 1 : 0; + header->u.meta_v3.capture_bw = tx_evt_param.bandwidth; + + bss_chan = wlan_vdev_mlme_get_bss_chan(vdev); + header->u.meta_v3.phy_mode = bss_chan->ch_phymode; + + header->u.meta_v3.prim20_chan = tx_evt_param.primary_20mhz_chan; + header->u.meta_v3.center_freq1 = tx_evt_param.band_center_freq1; + header->u.meta_v3.center_freq2 = tx_evt_param.band_center_freq2; + + /* Currently CFR data is captured on ACK of a Qos NULL frame. + * For 20 MHz, ACK is Legacy and for 40/80/160, ACK is DUP Legacy. + */ + header->u.meta_v3.capture_mode = tx_evt_param.bandwidth ? + CFR_DUP_LEGACY_ACK : CFR_LEGACY_ACK; + header->u.meta_v3.capture_type = tx_evt_param.capture_method; + header->u.meta_v3.num_rx_chain = wlan_vdev_mlme_get_rxchainmask(vdev); + header->u.meta_v3.sts_count = tx_evt_param.spatial_streams; + header->u.meta_v3.timestamp = tx_evt_param.timestamp_us; + + qdf_mem_copy(&header->u.meta_v3.peer_addr.su_peer_addr[0], + &tx_evt_param.peer_mac_addr.bytes[0], QDF_MAC_ADDR_SIZE); + qdf_mem_copy(&header->u.meta_v3.chain_rssi[0], + &tx_evt_param.chain_rssi[0], + HOST_MAX_CHAINS * sizeof(tx_evt_param.chain_rssi[0])); + qdf_mem_copy(&header->u.meta_v3.chain_phase[0], + &tx_evt_param.chain_phase[0], + HOST_MAX_CHAINS * sizeof(tx_evt_param.chain_phase[0])); + + status = correlate_and_relay_enh(pdev, cookie, lut, + CORRELATE_TX_EV_MODULE_ID); + if (status == STATUS_STREAM_AND_RELEASE) { + if (cfr_rx_ops->cfr_info_send) + status = cfr_rx_ops->cfr_info_send(pdev, + &lut->header, + sizeof( + struct + csi_cfr_header), + lut->data, + lut->data_len, + &end_magic, 4); + dump_metadata(header, cookie); + release_lut_entry_enh(pdev, lut); + target_if_dbr_buf_release(pdev, DBR_MODULE_CFR, buf_addr, + cookie, 0); + cfr_debug("Data sent to upper layers, " + "releasing look up table"); + } else if (status == STATUS_HOLD) { + cfr_debug("HOLD for buffer address: 0x%pK cookie: %u", + (void *)((uintptr_t)buf_addr), cookie); + } else { + cfr_err("Correlation returned invalid status!!"); + retval = -EINVAL; + goto end; + } + +end: + + wlan_objmgr_psoc_release_ref(psoc, WLAN_CFR_ID); + wlan_objmgr_vdev_release_ref(vdev, WLAN_CFR_ID); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return retval; +} +#else +static int +target_if_peer_capture_event(ol_scn_t sc, uint8_t *data, uint32_t datalen) +{ + return 0; +} +#endif + +/** + * target_if_register_tx_completion_enh_event_handler() - Register callback for + * WMI TX completion event + * @psoc: PSOC object + * + * Return: Success/Failure status + */ +int +target_if_register_tx_completion_enh_event_handler(struct wlan_objmgr_psoc + *psoc) +{ + /* Register completion handler here */ + wmi_unified_t wmi_hdl; + int ret = 0; + + wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_hdl) { + cfr_err("Unable to get wmi handle"); + return -EINVAL; + } + + ret = wmi_unified_register_event_handler(wmi_hdl, + wmi_peer_cfr_capture_event_id, + target_if_peer_capture_event, + WMI_RX_UMAC_CTX); + /* + * Event registration is called per pdev + * Ignore erorr if event is alreday registred. + */ + if (ret == QDF_STATUS_E_FAILURE) + ret = QDF_STATUS_SUCCESS; + + return ret; +} + +/** + * target_if_unregister_tx_completion_enh_event_handler() - Unregister callback + * for WMI TX completion event + * @psoc: PSOC object + * + * Return: Success/Failure status + */ +int +target_if_unregister_tx_completion_enh_event_handler(struct wlan_objmgr_psoc + *psoc) +{ + /* Unregister completion handler here */ + wmi_unified_t wmi_hdl; + int status = 0; + + wmi_hdl = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_hdl) { + cfr_err("Unable to get wmi handle"); + return -EINVAL; + } + + status = wmi_unified_unregister_event(wmi_hdl, + wmi_peer_cfr_capture_event_id); + return status; +} + +/** + * lut_ageout_timer_task() - Timer to flush pending TXRX/DBR events + * + * Return: none + */ +static os_timer_func(lut_ageout_timer_task) +{ + int i = 0; + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + struct look_up_table *lut = NULL; + uint64_t diff, cur_tstamp; + + OS_GET_TIMER_ARG(pcfr, struct pdev_cfr*); + + if (!pcfr) { + cfr_err("pdev object for CFR is null"); + return; + } + + pdev = pcfr->pdev_obj; + if (!pdev) { + cfr_err("pdev is null"); + return; + } + + if (wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID) + != QDF_STATUS_SUCCESS) { + cfr_err("failed to get pdev reference"); + return; + } + + cur_tstamp = qdf_ktime_to_ms(qdf_ktime_get()); + + for (i = 0; i < NUM_LUT_ENTRIES; i++) { + lut = get_lut_entry(pcfr, i); + if (!lut) + continue; + + if (lut->dbr_recv && !lut->tx_recv) { + diff = cur_tstamp - lut->dbr_tstamp; + if (diff > LUT_AGE_THRESHOLD) { + cfr_debug("<%d>TXRX event not received for " + "%llu ms, release lut entry : " + "dma_addr = 0x%pK\n", i, diff, + (void *)((uintptr_t)lut->dbr_address)); + target_if_dbr_buf_release(pdev, DBR_MODULE_CFR, + lut->dbr_address, + i, 0); + pcfr->flush_timeout_dbr_cnt++; + release_lut_entry_enh(pdev, lut); + } + } + } + + if (pcfr->lut_timer_init) + qdf_timer_mod(&pcfr->lut_age_timer, LUT_AGE_TIMER); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); +} + +/** + * target_if_cfr_start_lut_age_timer() - Start timer to flush aged-out LUT + * entries + * @pdev: pointer to pdev object + * + * Return: None + */ +void target_if_cfr_start_lut_age_timer(struct wlan_objmgr_pdev *pdev) +{ + struct pdev_cfr *pcfr; + + pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + if (pcfr->lut_timer_init) + qdf_timer_mod(&pcfr->lut_age_timer, LUT_AGE_TIMER); +} + +/** + * target_if_cfr_stop_lut_age_timer() - Stop timer to flush aged-out LUT + * entries + * @pdev: pointer to pdev object + * + * Return: None + */ +void target_if_cfr_stop_lut_age_timer(struct wlan_objmgr_pdev *pdev) +{ + struct pdev_cfr *pcfr; + + pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + if (pcfr->lut_timer_init) + qdf_timer_stop(&pcfr->lut_age_timer); +} + +/** + * target_if_cfr_update_global_cfg() - Update global config after a successful + * commit + * @pdev: pointer to pdev object + * + * Return: None + */ +void target_if_cfr_update_global_cfg(struct wlan_objmgr_pdev *pdev) +{ + int grp_id; + struct pdev_cfr *pcfr; + struct ta_ra_cfr_cfg *curr_cfg = NULL; + struct ta_ra_cfr_cfg *glbl_cfg = NULL; + unsigned long *modified_in_this_session; + + pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + modified_in_this_session = + (unsigned long *)&pcfr->rcc_param.modified_in_curr_session; + + for (grp_id = 0; grp_id < MAX_TA_RA_ENTRIES; grp_id++) { + if (qdf_test_bit(grp_id, modified_in_this_session)) { + /* Populating global config based on user's input */ + glbl_cfg = &pcfr->global[grp_id]; + curr_cfg = &pcfr->rcc_param.curr[grp_id]; + + if (curr_cfg->valid_ta) + qdf_mem_copy(glbl_cfg->tx_addr, + curr_cfg->tx_addr, + QDF_MAC_ADDR_SIZE); + + if (curr_cfg->valid_ra) + qdf_mem_copy(glbl_cfg->rx_addr, + curr_cfg->rx_addr, + QDF_MAC_ADDR_SIZE); + + if (curr_cfg->valid_ta_mask) + qdf_mem_copy(glbl_cfg->tx_addr_mask, + curr_cfg->tx_addr_mask, + QDF_MAC_ADDR_SIZE); + + if (curr_cfg->valid_ra_mask) + qdf_mem_copy(glbl_cfg->rx_addr_mask, + curr_cfg->rx_addr_mask, + QDF_MAC_ADDR_SIZE); + + if (curr_cfg->valid_bw_mask) + glbl_cfg->bw = curr_cfg->bw; + + if (curr_cfg->valid_nss_mask) + glbl_cfg->nss = curr_cfg->nss; + + if (curr_cfg->valid_mgmt_subtype) + glbl_cfg->mgmt_subtype_filter = + curr_cfg->mgmt_subtype_filter; + + if (curr_cfg->valid_ctrl_subtype) + glbl_cfg->ctrl_subtype_filter = + curr_cfg->ctrl_subtype_filter; + + if (curr_cfg->valid_data_subtype) + glbl_cfg->data_subtype_filter = + curr_cfg->data_subtype_filter; + } + } +} + +/** + * cfr_6018_init_pdev() - Inits cfr pdev and registers necessary handlers. + * @psoc: pointer to psoc object + * @pdev: pointer to pdev object + * + * Return: Registration status for necessary handlers + */ +QDF_STATUS cfr_6018_init_pdev(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct pdev_cfr *pcfr; + + if (!pdev) { + cfr_err("PDEV is NULL!"); + return QDF_STATUS_E_NULL_VALUE; + } + + pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + if (!pcfr) { + cfr_err("pcfr is NULL!"); + return QDF_STATUS_E_NULL_VALUE; + } + +#if DIRECT_BUF_RX_ENABLE + status = target_if_register_to_dbr_enh(pdev); + if (status != QDF_STATUS_SUCCESS) { + cfr_err("Failed to register with dbr"); + return status; + } +#endif + + status = target_if_register_tx_completion_enh_event_handler(psoc); + if (status != QDF_STATUS_SUCCESS) { + cfr_err("Failed to register with tx event handler"); + return status; + } + + pcfr->is_cfr_rcc_capable = 1; + pcfr->rcc_param.pdev_id = wlan_objmgr_pdev_get_pdev_id(pdev); + pcfr->rcc_param.modified_in_curr_session = MAX_RESET_CFG_ENTRY; + pcfr->rcc_param.num_grp_tlvs = MAX_TA_RA_ENTRIES; + + target_if_cfr_default_ta_ra_config(&pcfr->rcc_param, + true, MAX_RESET_CFG_ENTRY); + + status = target_if_cfr_config_rcc(pdev, &pcfr->rcc_param); + if (status == QDF_STATUS_SUCCESS) { + /* Update global configuration */ + target_if_cfr_update_global_cfg(pdev); + } else { + cfr_err("Sending WMI to configure default has failed\n"); + return status; + } + + pcfr->rcc_param.modified_in_curr_session = 0; + + pcfr->cfr_max_sta_count = MAX_CFR_ENABLED_CLIENTS; + pcfr->subbuf_size = STREAMFS_MAX_SUBBUF_CYP; + pcfr->num_subbufs = STREAMFS_NUM_SUBBUF_CYP; + + if (!pcfr->lut_timer_init) { + qdf_timer_init(NULL, + &(pcfr->lut_age_timer), + lut_ageout_timer_task, (void *)pcfr, + QDF_TIMER_TYPE_WAKE_APPS); + pcfr->lut_timer_init = 1; + } + + return status; +} + +/** + * cfr_6018_deinit_pdev() - De-inits corresponding pdev and handlers. + * @psoc: pointer to psoc object + * @pdev: pointer to pdev object + * + * Return: De-registration status for necessary handlers + */ +QDF_STATUS cfr_6018_deinit_pdev(struct wlan_objmgr_psoc *psoc, + struct wlan_objmgr_pdev *pdev) +{ + int status; + struct pdev_cfr *pcfr; + + pcfr = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + if (!pcfr) { + cfr_err("pcfr is NULL"); + return -EINVAL; + } + + if (pcfr->lut_timer_init) { + qdf_timer_stop(&pcfr->lut_age_timer); + qdf_timer_free(&(pcfr->lut_age_timer)); + pcfr->lut_timer_init = 0; + } + + pcfr->tx_evt_cnt = 0; + pcfr->dbr_evt_cnt = 0; + pcfr->release_cnt = 0; + pcfr->total_tx_evt_cnt = 0; + pcfr->rx_tlv_evt_cnt = 0; + pcfr->flush_dbr_cnt = 0; + pcfr->flush_timeout_dbr_cnt = 0; + pcfr->invalid_dma_length_cnt = 0; + pcfr->clear_txrx_event = 0; + pcfr->cfr_dma_aborts = 0; + qdf_mem_zero(&pcfr->rcc_param, sizeof(struct cfr_rcc_param)); + qdf_mem_zero(&pcfr->global, (sizeof(struct ta_ra_cfr_cfg) * + MAX_TA_RA_ENTRIES)); + +#ifdef DIRECT_BUF_RX_ENABLE + status = target_if_unregister_to_dbr_enh(pdev); + if (status != QDF_STATUS_SUCCESS) + cfr_err("Failed to register with dbr"); +#endif + + status = target_if_unregister_tx_completion_enh_event_handler(psoc); + if (status != QDF_STATUS_SUCCESS) + cfr_err("Failed to register with dbr"); + + return status; +} diff --git a/umac/cfr/core/inc/cfr_defs_i.h b/umac/cfr/core/inc/cfr_defs_i.h new file mode 100644 index 000000000000..9abee4a51852 --- /dev/null +++ b/umac/cfr/core/inc/cfr_defs_i.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _CFR_DEFS_I_H_ +#define _CFR_DEFS_I_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * wlan_cfr_psoc_obj_create_handler() - psoc object create handler for cfr + * @psoc - pointer to psoc object + * @args - void pointer in case it needs arguments + * + * Return: status of object creation + */ +QDF_STATUS +wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * wlan_cfr_psoc_obj_destroy_handler() - psoc object destroy handler for cfr + * @psoc - pointer to psoc object + * @args - void pointer in case it needs arguments + * + * Return: status of destroy object + */ +QDF_STATUS +wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc, void *arg); + +/** + * wlan_cfr_pdev_obj_create_handler() - pdev object create handler for cfr + * @pdev - pointer to pdev object + * @args - void pointer in case it needs arguments + * + * Return: status of object creation + */ +QDF_STATUS +wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg); + +/** + * wlan_cfr_pdev_obj_destroy_handler() - pdev object destroy handler for cfr + * @pdev - pointer to pdev object + * @args - void pointer in case it needs arguments + * + * Return: status of destroy object + */ +QDF_STATUS +wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg); + +/** + * wlan_cfr_peer_obj_create_handler() - peer object create handler for cfr + * @peer - pointer to peer object + * @args - void pointer in case it needs arguments + * + * Return: status of object creation + */ +QDF_STATUS +wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg); + +/** + * wlan_cfr_peer_obj_destroy_handler() - peer object destroy handler for cfr + * @peer - pointer to peer object + * @args - void pointer in case it needs arguments + * + * Return: status ofi destry object + */ +QDF_STATUS +wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg); + +/** + * cfr_streamfs_init() - stream filesystem init + * @pdev - pointer to pdev object + * + * Return: status of fs init + */ +QDF_STATUS +cfr_streamfs_init(struct wlan_objmgr_pdev *pdev); + +/** + * cfr_streamfs_remove() - stream filesystem remove + * @pdev - pointer to pdev object + * + * Return: status of fs remove + */ +QDF_STATUS +cfr_streamfs_remove(struct wlan_objmgr_pdev *pdev); + +/** + * cfr_streamfs_write() - write to stream filesystem + * @pa - pointer to pdev_cfr object + * @write_data - Pointer to data + * @write_len - data len + * + * Return: status of fs write + */ +QDF_STATUS +cfr_streamfs_write(struct pdev_cfr *pa, const void *write_data, + size_t write_len); + +/** + * cfr_streamfs_flush() - flush the write to streamfs + * @pa - pointer to pdev_cfr object + * + * Return: status of fs flush + */ +QDF_STATUS +cfr_streamfs_flush(struct pdev_cfr *pa); + +#endif diff --git a/umac/cfr/core/src/cfr_common.c b/umac/cfr/core/src/cfr_common.c new file mode 100644 index 000000000000..a963b43d2193 --- /dev/null +++ b/umac/cfr/core/src/cfr_common.c @@ -0,0 +1,323 @@ +/* + * Copyright (c) 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QDF_STATUS +wlan_cfr_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct psoc_cfr *cfr_sc = NULL; + + cfr_sc = (struct psoc_cfr *)qdf_mem_malloc(sizeof(struct psoc_cfr)); + if (NULL == cfr_sc) { + cfr_err("Failed to allocate cfr_ctx object\n"); + return QDF_STATUS_E_NOMEM; + } + + qdf_mem_zero(cfr_sc, sizeof(struct psoc_cfr)); + cfr_sc->psoc_obj = psoc; + + wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_CFR, + (void *)cfr_sc, + QDF_STATUS_SUCCESS); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_cfr_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc, void *arg) +{ + struct psoc_cfr *cfr_sc = NULL; + + cfr_sc = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_CFR); + if (NULL != cfr_sc) { + wlan_objmgr_psoc_component_obj_detach(psoc, WLAN_UMAC_COMP_CFR, + (void *)cfr_sc); + qdf_mem_free(cfr_sc); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_cfr_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg) +{ + struct pdev_cfr *pa = NULL; + + if (NULL == pdev) { + cfr_err("PDEV is NULL\n"); + return QDF_STATUS_E_FAILURE; + } + + pa = (struct pdev_cfr *)qdf_mem_malloc(sizeof(struct pdev_cfr)); + if (NULL == pa) { + cfr_err("Failed to allocate pdev_cfr object\n"); + return QDF_STATUS_E_NOMEM; + } + qdf_mem_zero(pa, sizeof(struct pdev_cfr)); + pa->pdev_obj = pdev; + + wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_CFR, + (void *)pa, QDF_STATUS_SUCCESS); + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_cfr_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg) +{ + struct pdev_cfr *pa = NULL; + + if (NULL == pdev) { + cfr_err("PDEV is NULL\n"); + return QDF_STATUS_E_FAILURE; + } + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + if (NULL != pa) { + wlan_objmgr_pdev_component_obj_detach(pdev, WLAN_UMAC_COMP_CFR, + (void *)pa); + qdf_mem_free(pa); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_cfr_peer_obj_create_handler(struct wlan_objmgr_peer *peer, void *arg) +{ + struct peer_cfr *pe = NULL; + + if (NULL == peer) { + cfr_err("PEER is NULL\n"); + return QDF_STATUS_E_FAILURE; + } + + pe = (struct peer_cfr *)qdf_mem_malloc(sizeof(struct peer_cfr)); + if (NULL == pe) { + cfr_err("Failed to allocate peer_cfr object\n"); + return QDF_STATUS_E_FAILURE; + } + + pe->peer_obj = peer; + + /* Remaining will be populated when we give CFR capture command */ + wlan_objmgr_peer_component_obj_attach(peer, WLAN_UMAC_COMP_CFR, + (void *)pe, QDF_STATUS_SUCCESS); + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS +wlan_cfr_peer_obj_destroy_handler(struct wlan_objmgr_peer *peer, void *arg) +{ + struct peer_cfr *pe = NULL; + struct wlan_objmgr_vdev *vdev; + struct wlan_objmgr_pdev *pdev = NULL; + struct pdev_cfr *pa = NULL; + + if (NULL == peer) { + cfr_err("PEER is NULL\n"); + return QDF_STATUS_E_FAILURE; + } + + vdev = wlan_peer_get_vdev(peer); + if (vdev) + pdev = wlan_vdev_get_pdev(vdev); + + if (pdev) + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, + WLAN_UMAC_COMP_CFR); + + pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR); + + if (pa && pe) { + if (pe->period && pe->request) + pa->cfr_current_sta_count--; + } + + if (NULL != pe) { + wlan_objmgr_peer_component_obj_detach(peer, WLAN_UMAC_COMP_CFR, + (void *)pe); + qdf_mem_free(pe); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * create_buf_file_handler() - Create streamfs buffer file + * @filename: base name of files to create, NULL for buffering only + * @parent: dentry of parent directory, NULL for root directory + * @mode: filemode + * @rchan_buf: streamfs channel buf + * + * Returns dentry if successful, NULL otherwise. + */ +static struct dentry *create_buf_file_handler(const char *filename, + struct dentry *parent, + umode_t mode, + struct rchan_buf *buf, + int *is_global) +{ + struct qal_dentry_t *buf_file; + *is_global = 1; + buf_file = qal_streamfs_create_file(filename, mode, + (struct qal_dentry_t *)parent, + (struct qal_streamfs_chan_buf *)buf); + + if (!buf_file) { + cfr_err("Chan buffer creation failed\n"); + return NULL; + } + + return (struct dentry *)buf_file; +} + +/** + * remove_buf_file_handler() - Remove streamfs buffer file + * @dentry:dentry + */ +static int remove_buf_file_handler(struct dentry *dentry) +{ + qal_streamfs_remove_file((struct qal_dentry_t *)dentry); + + return 0; +} + +static struct rchan_callbacks cfr_streamfs_cb = { + .create_buf_file = create_buf_file_handler, + .remove_buf_file = remove_buf_file_handler, +}; + +QDF_STATUS cfr_streamfs_init(struct wlan_objmgr_pdev *pdev) +{ + struct pdev_cfr *pa = NULL; + char folder[32]; + struct net_device *pdev_netdev; + struct ol_ath_softc_net80211 *scn; + struct target_pdev_info *tgt_hdl; + + if (pdev == NULL) { + cfr_err("PDEV is NULL\n"); + return QDF_STATUS_E_FAILURE; + } + + tgt_hdl = wlan_pdev_get_tgt_if_handle(pdev); + + if (!tgt_hdl) { + cfr_err("target_pdev_info is NULL\n"); + return QDF_STATUS_E_FAILURE; + } + + scn = target_pdev_get_feature_ptr(tgt_hdl); + pdev_netdev = scn->netdev; + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + + if (pa == NULL) { + cfr_err("pdev_cfr is NULL\n"); + return QDF_STATUS_E_FAILURE; + } + + if (!pa->is_cfr_capable) { + cfr_err("CFR IS NOT SUPPORTED\n"); + return QDF_STATUS_E_FAILURE; + } + + snprintf(folder, sizeof(folder), "cfr%s", pdev_netdev->name); + + pa->dir_ptr = qal_streamfs_create_dir((const char *)folder, NULL); + + if (!pa->dir_ptr) { + cfr_err("Directory create failed"); + return QDF_STATUS_E_FAILURE; + } + + pa->chan_ptr = qal_streamfs_open("cfr_dump", pa->dir_ptr, + pa->subbuf_size, pa->num_subbufs, + (struct qal_streamfs_chan_callbacks *)&cfr_streamfs_cb, + NULL); + + if (!pa->chan_ptr) { + cfr_err("Chan create failed"); + qal_streamfs_remove_dir_recursive(pa->dir_ptr); + pa->dir_ptr = NULL; + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cfr_streamfs_remove(struct wlan_objmgr_pdev *pdev) +{ + struct pdev_cfr *pa = NULL; + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + if (pa) { + if (pa->chan_ptr) { + qal_streamfs_close(pa->chan_ptr); + pa->chan_ptr = NULL; + } + + if (pa->dir_ptr) { + qal_streamfs_remove_dir_recursive(pa->dir_ptr); + pa->dir_ptr = NULL; + } + + } else + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cfr_streamfs_write(struct pdev_cfr *pa, const void *write_data, + size_t write_len) +{ + if (pa->chan_ptr) { + + /* write to channel buffer */ + qal_streamfs_write(pa->chan_ptr, (const void *)write_data, + write_len); + } else + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS cfr_streamfs_flush(struct pdev_cfr *pa) +{ + if (pa->chan_ptr) { + + /* Flush the data write to channel buffer */ + qal_streamfs_flush(pa->chan_ptr); + } else + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} diff --git a/umac/cfr/dispatcher/inc/wlan_cfr_tgt_api.h b/umac/cfr/dispatcher/inc/wlan_cfr_tgt_api.h new file mode 100644 index 000000000000..b9d3b283956c --- /dev/null +++ b/umac/cfr/dispatcher/inc/wlan_cfr_tgt_api.h @@ -0,0 +1,169 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _WLAN_CFR_TGT_API_H_ +#define _WLAN_CFR_TGT_API_H_ + +#include +#include +#include +#include + +/* tgt layer has APIs in application, to access functions in target + * through tx_ops. + */ + +/** + * tgt_cfr_init_pdev() - API that registers CFR to handlers. + * @pdev: pointer to pdev_object + * + * Return: success/failure of init + */ +int tgt_cfr_init_pdev(struct wlan_objmgr_pdev *pdev); + +/** + * tgt_cfr_deinit_pdev() - API that de-registers CFR to handlers. + * @pdev: pointer to pdev_object + * + * Return: success/failure of de-init + */ +int tgt_cfr_deinit_pdev(struct wlan_objmgr_pdev *pdev); + +/** + * tgt_cfr_get_target_type() - API to determine target type. + * @psoc: pointer to psoc_object + * + * Return: enum value of target type + */ +int tgt_cfr_get_target_type(struct wlan_objmgr_psoc *psoc); + +/** + * tgt_cfr_start_capture() - API to start cfr capture on a peer. + * @pdev: pointer to pdev_object + * @peer: pointer to peer_object + * @cfr_params: pointer to config cfr_params + * + * Return: success/failure of start capture + */ +int tgt_cfr_start_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer, + struct cfr_capture_params *cfr_params); + +/** + * tgt_cfr_stop_capture() - API to stop cfr capture on a peer. + * @pdev: pointer to pdev_object + * @peer: pointer to peer_object + * + * Return: success/failure of stop capture + */ +int tgt_cfr_stop_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer); + +/** + * tgt_cfr_enable_cfr_timer() - API to enable cfr timer + * @pdev: pointer to pdev_object + * @cfr_timer: Amount of time this timer has to run. If 0, it disables timer. + * + * Return: success/failure of timer enable + */ +int +tgt_cfr_enable_cfr_timer(struct wlan_objmgr_pdev *pdev, uint32_t cfr_timer); + +/** + * tgt_cfr_support_set() - API to set cfr support + * @psoc: pointer to psoc_object + * @value: value to be set + */ +void tgt_cfr_support_set(struct wlan_objmgr_psoc *psoc, uint32_t value); + +/** + * tgt_cfr_info_send() - API to send cfr info + * @pdev: pointer to pdev_object + * @head: pointer to cfr info head + * @hlen: head len + * @data: pointer to cfr info data + * @dlen: data len + * @tail: pointer to cfr info tail + * @tlen: tail len + * + * Return: success/failure of cfr info send + */ +uint32_t tgt_cfr_info_send(struct wlan_objmgr_pdev *pdev, void *head, + size_t hlen, void *data, size_t dlen, void *tail, + size_t tlen); + +#ifdef WLAN_ENH_CFR_ENABLE +/** + * tgt_cfr_config_rcc() - API to set RCC + * @pdev: pointer to pdev_object + * @rcc_param: rcc configurations + * + * Return: succcess / failure + */ +QDF_STATUS tgt_cfr_config_rcc(struct wlan_objmgr_pdev *pdev, + struct cfr_rcc_param *rcc_param); + +/** + * tgt_cfr_start_lut_age_timer() - API to start timer to flush aged out LUT + * entries + * @pdev: pointer to pdev_object + * + * Return: None + */ +void tgt_cfr_start_lut_age_timer(struct wlan_objmgr_pdev *pdev); + +/** + * tgt_cfr_stop_lut_age_timer() - API to stop timer to flush aged out LUT + * entries + * @pdev: pointer to pdev_object + * + * Return: None + */ +void tgt_cfr_stop_lut_age_timer(struct wlan_objmgr_pdev *pdev); + +/** + * tgt_cfr_default_ta_ra_cfg() - API to configure default values in TA_RA mode + * entries + * @pdev: pointer to pdev_object + * + * Return: none + */ +void tgt_cfr_default_ta_ra_cfg(struct wlan_objmgr_pdev *pdev, + struct cfr_rcc_param *rcc_param, + bool allvalid, uint16_t reset_cfg); + +/** + * tgt_cfr_dump_lut_enh() - Print all LUT entries + * @pdev: pointer to pdev_object + */ +void tgt_cfr_dump_lut_enh(struct wlan_objmgr_pdev *pdev); + +/** + * tgt_cfr_rx_tlv_process() - Process PPDU status TLVs + * @pdev_obj: pointer to pdev_object + * @nbuf: pointer to cdp_rx_indication_ppdu + */ +void tgt_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf); + +/** + * tgt_cfr_update_global_cfg() - Update global config after successful commit + * @pdev: pointer to pdev_object + */ +void tgt_cfr_update_global_cfg(struct wlan_objmgr_pdev *pdev); +#endif +#endif diff --git a/umac/cfr/dispatcher/inc/wlan_cfr_ucfg_api.h b/umac/cfr/dispatcher/inc/wlan_cfr_ucfg_api.h new file mode 100644 index 000000000000..b11772746a06 --- /dev/null +++ b/umac/cfr/dispatcher/inc/wlan_cfr_ucfg_api.h @@ -0,0 +1,267 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _WLAN_CFR_UCFG_API_H_ +#define _WLAN_CFR_UCFG_API_H_ + +#include +#include +#include + +#define MAX_CFR_PRD (10*60*1000) /* 10 minutes */ + +/** + * ucfg_cfr_start_capture() - function to start cfr capture for connected client + * @pdev: pointer to pdev object + * @peer: pointer to peer object + * @cfr_params: config params to cfr capture + * + * Return: status of start capture. + */ +int ucfg_cfr_start_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer, + struct cfr_capture_params *cfr_params); + +/** + * ucfg_cfr_stop_capture() - function to stop cfr capture for connected client + * @pdev: pointer to pdev object + * @peer: pointer to peer object + * + * Return: status of stop capture. + */ +int ucfg_cfr_stop_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer); + +/** + * ucfg_cfr_start_capture_probe_req() - function to start cfr capture for + * unassociated clients + * @pdev: pointer to pdev object + * @unassoc_mac: mac address of un-associated client + * @cfr_params: config params to cfr capture + * + * Return: status of start capture. + */ +int ucfg_cfr_start_capture_probe_req(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *unassoc_mac, + struct cfr_capture_params *params); + +/** + * ucfg_cfr_stop_capture_probe_req() - function to stop cfr capture for + * unassociated cleints + * @pdev: pointer to pdev object + * @unassoc_mac: mac address of un-associated client + * + * Return: status of stop capture. + */ +int ucfg_cfr_stop_capture_probe_req(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *unassoc_mac); + +/** + * ucfg_cfr_list_peers() - Lists total number of peers with cfr capture enabled + * @pdev: pointer to pdev object + * + * Return: number of peers with cfr capture enabled + */ +int ucfg_cfr_list_peers(struct wlan_objmgr_pdev *pdev); + +/** + * ucfg_cfr_set_timer() - function to enable cfr timer + * @pdev: pointer to pdev object + * @value: value to be set + * + * Return: status of timer enable + */ +int ucfg_cfr_set_timer(struct wlan_objmgr_pdev *pdev, uint32_t value); + +/** + * ucfg_cfr_get_timer() - function to get cfr_timer_enable + * @pdev: pointer to pdev object + * + * Return: value of cfr_timer_enable + */ +int ucfg_cfr_get_timer(struct wlan_objmgr_pdev *pdev); + +#ifdef WLAN_ENH_CFR_ENABLE +/* Channel capture recipe filters */ +enum capture_type { + RCC_DIRECTED_FTM_FILTER, + RCC_ALL_FTM_ACK_FILTER, + RCC_DIRECTED_NDPA_NDP_FILTER, + RCC_NDPA_NDP_ALL_FILTER, + RCC_TA_RA_FILTER, + RCC_ALL_PACKET_FILTER, + RCC_DIS_ALL_MODE, +}; + +/** + * ucfg_cfr_set_rcc_mode() - function to set RCC mode + * @vdev: pointer to vdev object + * @mode: capture type passed by user + * @value: Enable/Disable capture mode + * + * Return: status if the mode is set or not + */ +QDF_STATUS ucfg_cfr_set_rcc_mode(struct wlan_objmgr_vdev *vdev, + enum capture_type mode, uint8_t value); + +/** + * ucfg_cfr_get_rcc_enabled() - function to get RCC mode + * @vdev: pointer to vdev object + * + * Return: if the rcc is enabled or not + */ +bool ucfg_cfr_get_rcc_enabled(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_cfr_set_tara_config() - function to configure TA/RA address and mask + * @vdev: pointer to vdev object + * @params: user config + * + * Return: status + */ +QDF_STATUS ucfg_cfr_set_tara_config(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params); + +/** + * ucfg_cfr_set_bw_nss() - function to configure nss and bandwidth + * @vdev: pointer to vdev object + * @params: user config + * + * Return: status + */ +QDF_STATUS ucfg_cfr_set_bw_nss(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params); + +/** + * ucfg_cfr_set_frame_type_subtype() - function to configure frame type/subtype + * @vdev: pointer to vdev object + * @params: user config + * + * Return: status + */ +QDF_STATUS +ucfg_cfr_set_frame_type_subtype(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params); + +/** + * ucfg_cfr_set_capture_duration() - function to configure capture duration + * @vdev: pointer to vdev object + * @params: user config + * + * Return: status + */ +QDF_STATUS +ucfg_cfr_set_capture_duration(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params); + +/** + * ucfg_cfr_set_capture_interval() - function to configure capture interval + * @vdev: pointer to vdev object + * @params: user config + * + * Return: status + */ +QDF_STATUS +ucfg_cfr_set_capture_interval(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params); + +/** + * ucfg_cfr_set_en_bitmap() - function to configure 16-bit bitmap in TA_RA mode + * @vdev: pointer to vdev object + * @params: user config + * + * Return: status + */ +QDF_STATUS ucfg_cfr_set_en_bitmap(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params); + +/** + * ucfg_cfr_set_reset_bitmap() - function to clear all 9 params for all 16 + * groups in TA_RA mode + * @vdev: pointer to vdev object + * @params: user config + * + * Return: status + */ +QDF_STATUS ucfg_cfr_set_reset_bitmap(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params); + +/** + * ucfg_cfr_set_ul_mu_user_mask() - function to configure UL MU user mask + * @vdev: pointer to vdev object + * @params: user config + * + * Return: status + */ +QDF_STATUS +ucfg_cfr_set_ul_mu_user_mask(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params); + +/** + * ucfg_cfr_set_freeze_tlv_delay_cnt() - function to configure freeze TLV delay + * count threshold + * @vdev: pointer to vdev object + * @params: user config + * + * Return: status + */ +QDF_STATUS +ucfg_cfr_set_freeze_tlv_delay_cnt(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params); + +/** + * ucfg_cfr_committed_rcc_config() - function to commit user config + * @vdev: pointer to vdev object + * + * Return: status + */ +QDF_STATUS ucfg_cfr_committed_rcc_config(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_cfr_get_cfg() - function to display user config + * @vdev: pointer to vdev object + * + * Return: status + */ +QDF_STATUS ucfg_cfr_get_cfg(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_cfr_rcc_dump_dbg_counters() - function to display PPDU counters + * @vdev: pointer to vdev object + * + * Return: status + */ +QDF_STATUS ucfg_cfr_rcc_dump_dbg_counters(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_cfr_rcc_clr_dbg_counters() - function to clear CFR PPDU counters + * @vdev: pointer to vdev object + * + * Return: status + */ +QDF_STATUS ucfg_cfr_rcc_clr_dbg_counters(struct wlan_objmgr_vdev *vdev); + +/** + * ucfg_cfr_rcc_dump_lut() - function to display lookup table + * @vdev: pointer to vdev object + * + * Return: status + */ +QDF_STATUS ucfg_cfr_rcc_dump_lut(struct wlan_objmgr_vdev *vdev); +#endif +#endif diff --git a/umac/cfr/dispatcher/inc/wlan_cfr_utils_api.h b/umac/cfr/dispatcher/inc/wlan_cfr_utils_api.h new file mode 100644 index 000000000000..329acd53da8a --- /dev/null +++ b/umac/cfr/dispatcher/inc/wlan_cfr_utils_api.h @@ -0,0 +1,583 @@ +/* + * Copyright (c) 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. + */ + +#ifndef _WLAN_CFR_UTILS_API_H_ +#define _WLAN_CFR_UTILS_API_H_ + +#include +#include +#ifdef WLAN_ENH_CFR_ENABLE +#include +#endif + +#define cfr_alert(format, args...) \ + QDF_TRACE_FATAL(QDF_MODULE_ID_CFR, format, ## args) + +#define cfr_err(format, args...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_CFR, format, ## args) + +#define cfr_warn(format, args...) \ + QDF_TRACE_WARN(QDF_MODULE_ID_CFR, format, ## args) + +#define cfr_info(format, args...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_CFR, format, ## args) + +#define cfr_debug(format, args...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_CFR, format, ## args) + +#define DBR_EVENT_TIMEOUT_IN_MS_CFR 1 +#define DBR_NUM_RESP_PER_EVENT_CFR 1 +#define MAX_CFR_ENABLED_CLIENTS 10 +#ifdef WLAN_ENH_CFR_ENABLE +#define MAX_CFR_MU_USERS 4 +#define NUM_CHAN_CAPTURE_STATUS 4 +#define NUM_CHAN_CAPTURE_REASON 6 +#define MAX_TA_RA_ENTRIES 16 +#define MAX_RESET_CFG_ENTRY 0xFFFF +#endif + +enum cfrmetaversion { + CFR_META_VERSION_NONE, + CFR_META_VERSION_1, + CFR_META_VERSION_2, + CFR_META_VERSION_3, + CFR_META_VERSION_MAX = 0xFF, +}; + +enum cfrdataversion { + CFR_DATA_VERSION_NONE, + CFR_DATA_VERSION_1, + CFR_DATA_VERSION_MAX = 0xFF, +}; + +enum cfrplatformtype { + CFR_PLATFORM_TYPE_NONE, + CFR_PLATFORM_TYPE_MIPS, + CFR_PLATFORM_TYPE_ARM, + CFR_PLATFFORM_TYPE_MAX = 0xFF, +}; + +enum cfrradiotype { + CFR_CAPTURE_RADIO_NONE, + CFR_CAPTURE_RADIO_OSPREY, + CFR_CAPTURE_RADIO_PEAKCOCK, + CFR_CAPTURE_RADIO_SCORPION, + CFR_CAPTURE_RADIO_HONEYBEE, + CFR_CAPTURE_RADIO_DRAGONFLY, + CFR_CAPTURE_RADIO_JET, + CFR_CAPTURE_RADIO_PEREGRINE = 17, + CFR_CAPTURE_RADIO_SWIFT, + CFR_CAPTURE_RADIO_BEELINER, + CFR_CAPTURE_RADIO_CASCADE, + CFR_CAPTURE_RADIO_DAKOTA, + CFR_CAPTURE_RADIO_BESRA, + CFR_CAPTURE_RADIO_HKV2, + CFR_CAPTURE_RADIO_CYP, + CFR_CAPTURE_RADIO_MAX = 0xFF, +}; + +enum ack_capture_mode { + CFR_LEGACY_ACK = 0, + CFR_DUP_LEGACY_ACK = 1, + CFR_HT_ACK = 2, + CFR_VHT_ACK = 3, + CFR_INVALID_ACK, /*Always keep this at last*/ +}; + +/* Similar to WMI_PEER_CFR_CAPTURE_METHOD used in one-shot capture */ +enum cfr_capture_type { + CFR_TYPE_METHOD_NULL_FRAME = 0, + CFR_TYPE_METHOD_NULL_FRAME_WITH_PHASE = 1, + CFR_TYPE_METHOD_PROBE_RESP = 2, + CFR_TYPE_METHOD_TM = 3, + CFR_TYPE_METHOD_FTM = 4, + CFR_TYPE_METHOD_ACK_RESP_TO_TM_FTM = 5, + CFR_TYPE_METHOD_TA_RA_TYPE_FILTER = 6, + CFR_TYPE_METHOD_NDPA_NDP = 7, + CFR_TYPE_METHOD_ALL_PACKET = 8, + /* Add new capture methods before this line */ + CFR_TYPE_METHOD_LAST_VALID, + CFR_TYPE_METHOD_AUTO = 0xff, + CFR_TYPE_METHOD_MAX, +}; + +struct cfr_metadata_version_1 { + u_int8_t peer_addr[QDF_MAC_ADDR_SIZE]; + u_int8_t status; + u_int8_t capture_bw; + u_int8_t channel_bw; + u_int8_t phy_mode; + u_int16_t prim20_chan; + u_int16_t center_freq1; + u_int16_t center_freq2; + u_int8_t capture_mode; + u_int8_t capture_type; + u_int8_t sts_count; + u_int8_t num_rx_chain; + u_int32_t timestamp; + u_int32_t length; +} __attribute__ ((__packed__)); + +#define HOST_MAX_CHAINS 8 + +struct cfr_metadata_version_2 { + u_int8_t peer_addr[QDF_MAC_ADDR_SIZE]; + u_int8_t status; + u_int8_t capture_bw; + u_int8_t channel_bw; + u_int8_t phy_mode; + u_int16_t prim20_chan; + u_int16_t center_freq1; + u_int16_t center_freq2; + u_int8_t capture_mode; + u_int8_t capture_type; + u_int8_t sts_count; + u_int8_t num_rx_chain; + u_int32_t timestamp; + u_int32_t length; + u_int32_t chain_rssi[HOST_MAX_CHAINS]; + u_int16_t chain_phase[HOST_MAX_CHAINS]; +} __attribute__ ((__packed__)); + +#ifdef WLAN_ENH_CFR_ENABLE +struct cfr_metadata_version_3 { + u_int8_t status; + u_int8_t capture_bw; + u_int8_t channel_bw; + u_int8_t phy_mode; + u_int16_t prim20_chan; + u_int16_t center_freq1; + u_int16_t center_freq2; + u_int8_t capture_mode; /* ack_capture_mode */ + u_int8_t capture_type; /* cfr_capture_type */ + u_int8_t sts_count; + u_int8_t num_rx_chain; + u_int32_t timestamp; + u_int32_t length; + u_int8_t is_mu_ppdu; + u_int8_t num_mu_users; + union { + u_int8_t su_peer_addr[QDF_MAC_ADDR_SIZE]; + u_int8_t mu_peer_addr[MAX_CFR_MU_USERS][QDF_MAC_ADDR_SIZE]; + } peer_addr; + u_int32_t chain_rssi[HOST_MAX_CHAINS]; + u_int16_t chain_phase[HOST_MAX_CHAINS]; +} __attribute__ ((__packed__)); +#endif + +struct csi_cfr_header { + u_int32_t start_magic_num; + u_int32_t vendorid; + u_int8_t cfr_metadata_version; + u_int8_t cfr_data_version; + u_int8_t chip_type; + u_int8_t pltform_type; + u_int32_t Reserved; + + union { + struct cfr_metadata_version_1 meta_v1; + struct cfr_metadata_version_2 meta_v2; +#ifdef WLAN_ENH_CFR_ENABLE + struct cfr_metadata_version_3 meta_v3; +#endif + } u; +} __attribute__ ((__packed__)); + +/** + * struct cfr_capture_params - structure to store cfr config param + * bandwidth: bandwitdh of capture + * period: period of capture + * method: enum of method being followed to capture cfr data. 0-QoS null data + */ +struct cfr_capture_params { + u_int8_t bandwidth; + u_int32_t period; + u_int8_t method; +}; + +/** + * struct psoc_cfr - private psoc object for cfr + * psoc_obj: pointer to psoc object + * is_cfr_capable: flag to determine if cfr is enabled or not + */ +struct psoc_cfr { + struct wlan_objmgr_psoc *psoc_obj; + uint8_t is_cfr_capable; +}; + +/** + * struct cfr_wmi_host_mem_chunk - wmi mem chunk related + * vaddr: pointer to virtual address + * paddr: physical address + * len: len of the mem chunk allocated + * req_id: reqid related to the mem chunk + */ +struct cfr_wmi_host_mem_chunk { + uint32_t *vaddr; + uint32_t paddr; + uint32_t len; + uint32_t req_id; +}; + +struct whal_cfir_dma_hdr { + uint16_t + // 'BA' + tag : 8, + // '02', length of header in 4 octet units + length : 6, + // 00 + reserved : 2; + uint16_t + // [16] + upload_done : 1, + // [17:18], 0: invalid, 1: CFR, 2: CIR, 3: DebugH + capture_type : 3, + // [19:20], 0: Legacy, 1: HT, 2: VHT, 3: HE + preamble_type : 2, + // [21:23], 0: 1-stream, 1: 2-stream, ..., 7: 8-stream + nss : 3, + // [24:27], 0: invalid, 1: 1-chain, 2: 2-chain, etc. + num_chains : 3, + // [28:30], 0: 20 MHz, 1: 40 MHz, 2: 80 MHz, 3: 160 MHz + upload_pkt_bw : 3, // [31] + sw_peer_id_valid : 1; + uint16_t + sw_peer_id : 16; // [15:0] + uint16_t + phy_ppdu_id : 16; // [15:0] +}; + +#define MAX_LUT_ENTRIES 140 /* For HKv2 136 is max */ + +/** + * struct look_up_table - Placeholder for 2 asynchronous events (DBR and + * TXRX event) + * dbr_recv: Indicates whether WMI for DBR completion is received or not + * tx_recv: Indicates whether WMI for TX completion (or) WDI event for RX + * status is received or not + * data: pointer to CFR data that ucode DMAs to host memory + * data_len: length of CFR data DMAed by ucode + * dbr_ppdu_id: PPDU id retrieved from DBR completion WMI event + * tx_ppdu_id: PPDU id retrieved from WMI TX completion event (or) PPDU status + * TLV + * dbr_address: Physical address of the CFR data dump retrieved from DBR + * completion WMI event + * tx_address1: Physical address of the CFR data from TX/RX event + * tx_address2: Physical address of the CFR data from TX/RX event + * csi_cfr_header: CFR header constructed by host + * whal_cfir_enhanced_hdr: CFR header constructed by ucode + * tx_tstamp: Timestamp when TX/RX event was received + * dbr_tstamp: Timestamp when DBR completion event was received + * header_length: Length of header DMAed by ucode in words + * payload_length: Length of CFR payload + */ +struct look_up_table { + bool dbr_recv; + bool tx_recv; + uint8_t *data; /* capture payload */ + uint32_t data_len; /* capture len */ + uint16_t dbr_ppdu_id; /* ppdu id from dbr */ + uint16_t tx_ppdu_id; /* ppdu id from TX event */ + qdf_dma_addr_t dbr_address; /* capture len */ + uint32_t tx_address1; /* capture len */ + uint32_t tx_address2; /* capture len */ + struct csi_cfr_header header; + struct whal_cfir_dma_hdr dma_hdr; + uint64_t txrx_tstamp; + uint64_t dbr_tstamp; + uint32_t header_length; + uint32_t payload_length; +}; + +struct unassoc_pool_entry { + struct qdf_mac_addr mac; + struct cfr_capture_params cfr_params; + bool is_valid; +}; + +#ifdef WLAN_ENH_CFR_ENABLE +/** + * struct ta_ra_cfr_cfg - structure to store configuration of 16 groups in + * M_TA_RA mode + * filter_group_id: Filter group number for which the below filters needs to be + * applied + * bw: CFR capture will be done for packets matching the bandwidths specified + * within this bitmask + * nss: CFR capture will be done for packets matching the Nss specified within + * this bitmask + * valid_ta: Ta_addr is valid if set + * valid_ta_mask: Ta_addr_mask is valid if set + * valid_ra: Ra_addr is valid if set + * valid_ra_mask: Ra_addr_mask is valid if set + * valid_bw_mask: Bandwidth is valid if set + * valid_nss_mask: NSS is valid if set + * valid_mgmt_subtype: Mgmt_subtype is valid if set + * valid_ctrl_subtype: Ctrl_subtype is valid if set + * valid_data_subtype: Data_subtype is valid if set + * mgmt_subtype_filter: Managments Packets matching the subtype filter + * categories will be filtered in by MAC for CFR capture. + * ctrl_subtype_filter: Control Packets matching the subtype filter + * categories will be filtered in by MAC for CFR capture. + * data_subtype_filter: Data Packets matching the subtype filter + * categories will be filtered in by MAC for CFR capture. + * tx_addr: Packets whose transmitter address matches (tx_addr & tx_addr_mask) + * will be filtered in by MAC + * tx_addr_mask: Packets whose transmitter address matches (tx_addr & + * tx_addr_mask) will be filtered in by MAC + * rx_addr: Packets whose receiver address matches (rx_addr & rx_addr_mask) + * will be filtered in by MAC + * rx_addr_mask: Packets whose receiver address matches (rx_addr & + * rx_addr_mask) will be filtered in by MAC + */ +struct ta_ra_cfr_cfg { + uint8_t filter_group_id; + uint16_t bw :5, + nss :8, + rsvd0 :3; + uint16_t valid_ta :1, + valid_ta_mask :1, + valid_ra :1, + valid_ra_mask :1, + valid_bw_mask :1, + valid_nss_mask :1, + valid_mgmt_subtype :1, + valid_ctrl_subtype :1, + valid_data_subtype :1, + rsvd1 :7; + uint16_t mgmt_subtype_filter; + uint16_t ctrl_subtype_filter; + uint16_t data_subtype_filter; + uint8_t tx_addr[QDF_MAC_ADDR_SIZE]; + uint8_t rx_addr[QDF_MAC_ADDR_SIZE]; + uint8_t tx_addr_mask[QDF_MAC_ADDR_SIZE]; + uint8_t rx_addr_mask[QDF_MAC_ADDR_SIZE]; + +} qdf_packed; + +/** + * struct cfr_rcc_param - structure to store cfr config param + * pdev_id: pdev_id for identifying the MAC + * capture_duration: Capture Duration field for which CFR capture has to happen, + * in microsecond units + * capture_interval: Capture interval field which is time in between + * consecutive CFR capture, in microsecond units + * ul_mu_user_mask_lower: Bitfields indicates which of the users in the current + * UL MU tranmission are enabled for CFR capture. + * ul_mu_user_mask_upper: This is contiuation of the above lower mask. + * freeze_tlv_delay_cnt_en: Enable Freeze TLV delay counter in MAC + * freeze_tlv_delay_cnt_thr: Indicates the number of consecutive Rx packets to + * be skipped before CFR capture is enabled again. + * filter_group_bitmap: Bitfields set indicates which of the CFR group config is + * enabled + * m_directed_ftm: Filter Directed FTM ACK frames for CFR capture + * m_all_ftm_ack: Filter All FTM ACK frames for CFR capture + * m_ndpa_ndp_directed: Filter NDPA NDP Directed Frames for CFR capture + * m_ndpa_ndp_all: Filter all NDPA NDP for CFR capture + * m_ta_ra_filter: Filter Frames based on TA/RA/Subtype as provided in CFR Group + * config + * m_all_packet: Filter in All packets for CFR Capture + * num_grp_tlvs: Indicates the number of groups in M_TA_RA mode, that have + * changes in the current commit session, use to construct WMI group TLV(s) + * curr: Placeholder for M_TA_RA group config in current commit session + * modified_in_curr_session: Bitmap indicating number of groups in M_TA_RA mode + * that have changed in current commit session. + */ +struct cfr_rcc_param { + uint8_t pdev_id; + uint32_t capture_duration; + uint32_t capture_interval; + uint32_t ul_mu_user_mask_lower; + uint32_t ul_mu_user_mask_upper; + uint16_t freeze_tlv_delay_cnt_en :1, + freeze_tlv_delay_cnt_thr :8, + rsvd0 :7; + uint16_t filter_group_bitmap; + uint8_t m_directed_ftm : 1, + m_all_ftm_ack : 1, + m_ndpa_ndp_directed : 1, + m_ndpa_ndp_all : 1, + m_ta_ra_filter : 1, + m_all_packet : 1, + rsvd1 : 2; + uint8_t num_grp_tlvs; + + struct ta_ra_cfr_cfg curr[MAX_TA_RA_ENTRIES]; + uint16_t modified_in_curr_session; +}; +#endif /* WLAN_ENH_CFR_ENABLE */ + +/** + * struct pdev_cfr - private pdev object for cfr + * pdev_obj: pointer to pdev object + * is_cfr_capable: flag to determine if cfr is enabled or not + * cfr_timer_enable: flag to enable/disable timer + * cfr_mem_chunk: Region of memory used for storing cfr data + * cfr_max_sta_count: Maximum stations supported in one-shot capture mode + * num_subbufs: No. of sub-buffers used in relayfs + * subbuf_size: Size of sub-buffer used in relayfs + * chan_ptr: Channel in relayfs + * dir_ptr: Parent directory of relayfs file + * lut: lookup table used to store asynchronous DBR and TX/RX events for + * correlation + * dbr_buf_size: Size of DBR completion buffer + * dbr_num_bufs: No. of DBR completions + * tx_evt_cnt: No. of TX completion events till CFR stop was issued + * total_tx_evt_cnt: No. of Tx completion events since wifi was up + * dbr_evt_cnt: No. of WMI DBR completion events + * release_cnt: No. of CFR data buffers relayed to userspace + * rcc_param: Structure to store CFR config for the current commit session + * global: Structure to store accumulated CFR config + * rx_tlv_evt_cnt: Number of CFR WDI events from datapath + * lut_age_timer: Timer to flush pending TXRX/DBR events in lookup table + * lut_timer_init: flag to determine if lut_age_timer is initialized or not + * is_cfr_rcc_capable: Flag to determine if RCC is enabled or not. + * flush_dbr_cnt: No. of un-correlated DBR completions flushed when a newer PPDU + * is correlated successfully with newer DBR completion + * invalid_dma_length_cnt: No. of buffers for which CFR DMA header length (or) + * data length was invalid + * flush_timeout_dbr_cnt: No. of DBR completion flushed out in ageout logic + * clear_txrx_event: No. of PPDU status TLVs over-written in LUT + * unassoc_pool: Pool of un-associated clients used when capture method is + * CFR_CAPTURE_METHOD_PROBE_RESPONSE + * last_success_tstamp: DBR timestamp which indicates that both DBR and TX/RX + * events have been received successfully. + * cfr_dma_aborts: No. of CFR DMA aborts in ucode + */ +/* + * To be extended if we get more capbality info + * from FW's extended service ready event. + */ +struct pdev_cfr { + struct wlan_objmgr_pdev *pdev_obj; + uint8_t is_cfr_capable; + uint8_t cfr_timer_enable; + struct cfr_wmi_host_mem_chunk cfr_mem_chunk; + uint16_t cfr_max_sta_count; + uint16_t cfr_current_sta_count; + uint32_t num_subbufs; + uint32_t subbuf_size; + struct qal_streamfs_chan *chan_ptr; + struct qal_dentry_t *dir_ptr; + struct look_up_table lut[MAX_LUT_ENTRIES]; + uint32_t dbr_buf_size; + uint32_t dbr_num_bufs; + uint64_t tx_evt_cnt; + uint64_t total_tx_evt_cnt; + uint64_t dbr_evt_cnt; + uint64_t release_cnt; +#ifdef WLAN_ENH_CFR_ENABLE + struct cfr_rcc_param rcc_param; + struct ta_ra_cfr_cfg global[MAX_TA_RA_ENTRIES]; + uint64_t rx_tlv_evt_cnt; + qdf_timer_t lut_age_timer; + uint8_t lut_timer_init; + uint8_t is_cfr_rcc_capable; + uint64_t flush_dbr_cnt; + uint64_t invalid_dma_length_cnt; + uint64_t flush_timeout_dbr_cnt; + uint64_t clear_txrx_event; + uint64_t last_success_tstamp; + uint64_t cfr_dma_aborts; +#endif + struct unassoc_pool_entry unassoc_pool[MAX_CFR_ENABLED_CLIENTS]; +}; + +#define PEER_CFR_CAPTURE_ENABLE 1 +#define PEER_CFR_CAPTURE_DISABLE 0 +/** + * struct peer_cfr - private peer object for cfr + * peer_obj: pointer to peer_obj + * request: Type of request (start/stop) + * bandwidth: bandwitdth of capture for this peer + * capture_method: enum determining type of cfr data capture. + * 0-Qos null data + */ +struct peer_cfr { + struct wlan_objmgr_peer *peer_obj; + u_int8_t request; /* start/stop */ + u_int8_t bandwidth; + u_int32_t period; + u_int8_t capture_method; +}; + +/** + * cfr_initialize_pdev() - cfr initialize pdev + * @pdev: Pointer to pdev_obj + * + * Return: status of cfr pdev init + */ +QDF_STATUS cfr_initialize_pdev(struct wlan_objmgr_pdev *pdev); + +/** + * cfr_deinitialize_pdev() - cfr deinitialize pdev + * @pdev: Pointer to pdev_obj + * + * Return: status of cfr pdev deinit + */ +QDF_STATUS cfr_deinitialize_pdev(struct wlan_objmgr_pdev *pdev); + +/** + * wlan_cfr_init() - Global init for cfr. + * + * Return: status of global init pass/fail + */ +QDF_STATUS wlan_cfr_init(void); + +/** + * wlan_cfr_deinit() - Global de-init for cfr. + * + * Return: status of global de-init pass/fail + */ +QDF_STATUS wlan_cfr_deinit(void); + +/** + * wlan_cfr_pdev_open() - pdev_open function for cfr. + * @pdev: pointer to pdev object + * + * Return: status of pdev_open pass/fail + */ +QDF_STATUS wlan_cfr_pdev_open(struct wlan_objmgr_pdev *pdev); + +/** + * wlan_cfr_pdev_close() - pdev_close function for cfr. + * @pdev: pointer to pdev object + * + * Return: status of pdev_close pass/fail + */ +QDF_STATUS wlan_cfr_pdev_close(struct wlan_objmgr_pdev *pdev); + +/** + * count_set_bits() - function to count set bits in a bitmap + * @value: input bitmap + * + * Return: No. of set bits + */ +uint8_t count_set_bits(uint32_t value); + +#ifdef WLAN_ENH_CFR_ENABLE +/** + * wlan_cfr_rx_tlv_process() - Process PPDU status TLVs and store info in + * lookup table + * @pdev_obj: PDEV object + * @nbuf: ppdu info + * + * Return: none + */ +void wlan_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf); +#endif +#endif diff --git a/umac/cfr/dispatcher/src/wlan_cfr_tgt_api.c b/umac/cfr/dispatcher/src/wlan_cfr_tgt_api.c new file mode 100644 index 000000000000..93b6075188c4 --- /dev/null +++ b/umac/cfr/dispatcher/src/wlan_cfr_tgt_api.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 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. + */ + +/* + * Layer b/w umac and target_if (ol) txops + * It contains wrapers for txops + */ + +#include +#include +#include +#include + +uint32_t tgt_cfr_info_send(struct wlan_objmgr_pdev *pdev, void *head, + size_t hlen, void *data, size_t dlen, void *tail, + size_t tlen) +{ + struct pdev_cfr *pa; + uint32_t status; + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + + if (pa == NULL) { + cfr_err("pdev_cfr is NULL\n"); + return -1; + } + + if (head) + status = cfr_streamfs_write(pa, (const void *)head, hlen); + + if (data) + status = cfr_streamfs_write(pa, (const void *)data, dlen); + + if (tail) + status = cfr_streamfs_write(pa, (const void *)tail, tlen); + + + /* finalise the write */ + status = cfr_streamfs_flush(pa); + + return status; +} + +void tgt_cfr_support_set(struct wlan_objmgr_psoc *psoc, uint32_t value) +{ + struct psoc_cfr *cfr_sc; + + if (psoc == NULL) + return; + + cfr_sc = wlan_objmgr_psoc_get_comp_private_obj(psoc, + WLAN_UMAC_COMP_CFR); + if (cfr_sc == NULL) + return; + + cfr_sc->is_cfr_capable = !!value; + cfr_debug("CFR:%s FW support advert=%d\n", __func__, + cfr_sc->is_cfr_capable); +} + +static inline struct wlan_lmac_if_cfr_tx_ops * + wlan_psoc_get_cfr_txops(struct wlan_objmgr_psoc *psoc) +{ + return &((psoc->soc_cb.tx_ops.cfr_tx_ops)); +} + +int tgt_cfr_get_target_type(struct wlan_objmgr_psoc *psoc) +{ + uint32_t target_type = 0; + struct wlan_lmac_if_target_tx_ops *target_type_tx_ops; + + target_type_tx_ops = &psoc->soc_cb.tx_ops.target_tx_ops; + + if (target_type_tx_ops->tgt_get_tgt_type) + target_type = target_type_tx_ops->tgt_get_tgt_type(psoc); + + return target_type; +} + +int tgt_cfr_init_pdev(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + int status = 0; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_init_pdev) + status = cfr_tx_ops->cfr_init_pdev(psoc, pdev); + + if (status != 0) + cfr_err("Error occurred with exit code %d\n", status); + + return status; +} + +int tgt_cfr_deinit_pdev(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + int status = 0; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_deinit_pdev) + status = cfr_tx_ops->cfr_deinit_pdev(psoc, pdev); + + if (status != 0) + cfr_err("Error occurred with exit code %d\n", status); + + return status; +} + +int tgt_cfr_start_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer, + struct cfr_capture_params *cfr_params) +{ + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + int status = 0; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_start_capture) + status = cfr_tx_ops->cfr_start_capture(pdev, peer, cfr_params); + + if (status != 0) + cfr_err("Error occurred with exit code %d\n", status); + + return status; +} + +int tgt_cfr_stop_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer) +{ + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + int status = 0; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_stop_capture) + status = cfr_tx_ops->cfr_stop_capture(pdev, peer); + + if (status != 0) + cfr_err("Error occurred with exit code %d\n", status); + + return status; +} + +int +tgt_cfr_enable_cfr_timer(struct wlan_objmgr_pdev *pdev, uint32_t cfr_timer) +{ + int status = 0; + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_enable_cfr_timer) + status = cfr_tx_ops->cfr_enable_cfr_timer(pdev, cfr_timer); + + if (status != 0) + cfr_err("Error occurred with exit code %d\n", status); + + return status; +} + +#ifdef WLAN_ENH_CFR_ENABLE +QDF_STATUS +tgt_cfr_config_rcc(struct wlan_objmgr_pdev *pdev, + struct cfr_rcc_param *rcc_param) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_config_rcc) + status = cfr_tx_ops->cfr_config_rcc(pdev, rcc_param); + + if (status != QDF_STATUS_SUCCESS) + cfr_err("Error occurred with exit code %d\n", status); + + return status; +} + +void tgt_cfr_start_lut_age_timer(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + if (!psoc) { + cfr_err("Invalid PSOC: Flush LUT Timer cannot be started\n"); + return; + } + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_start_lut_timer) + cfr_tx_ops->cfr_start_lut_timer(pdev); +} + +void tgt_cfr_stop_lut_age_timer(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + if (!psoc) { + cfr_err("Invalid PSOC: Flush LUT Timer cannot be stopped\n"); + return; + } + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_stop_lut_timer) + cfr_tx_ops->cfr_stop_lut_timer(pdev); +} + +void tgt_cfr_default_ta_ra_cfg(struct wlan_objmgr_pdev *pdev, + struct cfr_rcc_param *rcc_param, + bool allvalid, uint16_t reset_cfg) +{ + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_default_ta_ra_cfg) + cfr_tx_ops->cfr_default_ta_ra_cfg(rcc_param, + allvalid, reset_cfg); +} + +void tgt_cfr_dump_lut_enh(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_dump_lut_enh) + cfr_tx_ops->cfr_dump_lut_enh(pdev); +} + +void tgt_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf) +{ + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_rx_tlv_process) + cfr_tx_ops->cfr_rx_tlv_process(pdev, nbuf); +} + +void tgt_cfr_update_global_cfg(struct wlan_objmgr_pdev *pdev) +{ + struct wlan_lmac_if_cfr_tx_ops *cfr_tx_ops = NULL; + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + if (!psoc) { + cfr_err("Invalid PSOC:Cannot update global config.\n"); + return; + } + + cfr_tx_ops = wlan_psoc_get_cfr_txops(psoc); + + if (cfr_tx_ops->cfr_update_global_cfg) + cfr_tx_ops->cfr_update_global_cfg(pdev); +} +#endif diff --git a/umac/cfr/dispatcher/src/wlan_cfr_ucfg_api.c b/umac/cfr/dispatcher/src/wlan_cfr_ucfg_api.c new file mode 100644 index 000000000000..482366568d94 --- /dev/null +++ b/umac/cfr/dispatcher/src/wlan_cfr_ucfg_api.c @@ -0,0 +1,1104 @@ +/* + * Copyright (c) 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 +#include "../../core/inc/cfr_defs_i.h" +#include +#include +#include +#include +#ifdef WLAN_ENH_CFR_ENABLE +#include "cdp_txrx_ctrl.h" +#endif + +int ucfg_cfr_start_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer, + struct cfr_capture_params *params) +{ + int status; + struct pdev_cfr *pa; + struct peer_cfr *pe; + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + if (NULL == pa) { + cfr_err("PDEV cfr object is NULL!\n"); + return -EINVAL; + } + + if (!(pa->is_cfr_capable)) { + qdf_info("cfr is not supported on this chip\n"); + return -EINVAL; + } + + /* Get peer private object */ + pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR); + if (NULL == pe) { + cfr_err("PEER cfr object is NULL!\n"); + return -EINVAL; + } + + if ((params->period < 0) || (params->period > MAX_CFR_PRD) || + (params->period % 10)) { + cfr_err("Invalid period value: %d\n", params->period); + return -EINVAL; + } + + if (!(params->period) && (pa->cfr_timer_enable)) { + cfr_err("Single shot capture is not allowed during periodic capture\n"); + return -EINVAL; + } + + if ((params->period) && !(pa->cfr_timer_enable)) { + cfr_err("Global periodic timer is not enabled, configure global cfr timer\n"); + } + + if (params->period) { + if (pa->cfr_current_sta_count == pa->cfr_max_sta_count) { + qdf_info("max periodic cfr clients reached\n"); + return -EINVAL; + } + if (!(pe->request)) + pa->cfr_current_sta_count++; + } + + status = tgt_cfr_start_capture(pdev, peer, params); + + if (status == 0) { + pe->bandwidth = params->bandwidth; + pe->period = params->period; + pe->capture_method = params->method; + pe->request = PEER_CFR_CAPTURE_ENABLE; + } else + pa->cfr_current_sta_count--; + + return status; +} + +int ucfg_cfr_start_capture_probe_req(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *unassoc_mac, + struct cfr_capture_params *params) +{ + int idx, idx_to_insert = -1; + struct pdev_cfr *pa; + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + if (!pa) { + cfr_err("Pdev cfr object is null!"); + return -EINVAL; + } + + if (!(pa->is_cfr_capable)) { + cfr_err("CFR is not supported on this chip"); + return -EINVAL; + } + + if (pa->cfr_current_sta_count == pa->cfr_max_sta_count) { + cfr_err("max cfr cleint reached"); + return -EINVAL; + } + + for (idx = 0; idx < MAX_CFR_ENABLED_CLIENTS; idx++) { + /* Store first invalid entry's index, to add mac entry if not + * already present. + */ + if (idx_to_insert < 0) { + if (pa->unassoc_pool[idx].is_valid != true) + idx_to_insert = idx; + } + + /* Add new mac entry only if it is not present. If already + * present, update the capture parameters + */ + if (qdf_mem_cmp(&pa->unassoc_pool[idx].mac, unassoc_mac, + sizeof(struct qdf_mac_addr)) == 0) { + cfr_info("Node already present. Updating params"); + qdf_mem_copy(&pa->unassoc_pool[idx].cfr_params, + params, + sizeof(struct cfr_capture_params)); + pa->unassoc_pool[idx].is_valid = true; + return 0; + } + } + + if (idx_to_insert < 0) { + /* All the entries in the table are valid. So we have reached + * max client capacity. To add a new client, capture on one of + * the clients in table has to be stopped. + */ + cfr_err("Maximum client capacity reached"); + return -EINVAL; + } + + /* If control reaches here, we did not find mac in the table + * and we have atleast one free entry in table. + * Add the entry at index = idx_to_insert + */ + qdf_mem_copy(&pa->unassoc_pool[idx_to_insert].mac, + unassoc_mac, sizeof(struct qdf_mac_addr)); + qdf_mem_copy(&pa->unassoc_pool[idx_to_insert].cfr_params, + params, sizeof(struct cfr_capture_params)); + pa->unassoc_pool[idx_to_insert].is_valid = true; + pa->cfr_current_sta_count++; + + return 0; +} + +int ucfg_cfr_stop_capture_probe_req(struct wlan_objmgr_pdev *pdev, + struct qdf_mac_addr *unassoc_mac) +{ + struct pdev_cfr *pa; + int idx; + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + if (!pa) { + cfr_err("Pdev cfr object is NULL!\n"); + return -EINVAL; + } + + if (!(pa->is_cfr_capable)) { + cfr_err("CFR is not supported on this chip\n"); + return -EINVAL; + } + + for (idx = 0; idx < MAX_CFR_ENABLED_CLIENTS; idx++) { + /* Remove mac only if it is present */ + if (qdf_mem_cmp(&pa->unassoc_pool[idx].mac, unassoc_mac, + sizeof(struct qdf_mac_addr)) == 0) { + qdf_mem_zero(&pa->unassoc_pool[idx], + sizeof(struct unassoc_pool_entry)); + pa->cfr_current_sta_count--; + return 0; + } + } + + /* If mac was present in pool it would have been deleted in the + * above loop and returned from there. + * If control reached here, mac was not found. So, ignore the request. + */ + cfr_err("Trying to delete mac not present in pool. Ignoring request."); + return 0; +} + +int ucfg_cfr_set_timer(struct wlan_objmgr_pdev *pdev, uint32_t value) +{ + struct pdev_cfr *pa; + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + if (pa == NULL) { + cfr_err("PDEV cfr object is NULL!\n"); + return -EINVAL; + } + + if (!(pa->is_cfr_capable)) { + qdf_info("cfr is not supported on this chip\n"); + return -EINVAL; + } + + return tgt_cfr_enable_cfr_timer(pdev, value); +} +qdf_export_symbol(ucfg_cfr_set_timer); + +int ucfg_cfr_get_timer(struct wlan_objmgr_pdev *pdev) +{ + struct pdev_cfr *pa; + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + if (pa == NULL) { + cfr_err("PDEV cfr object is NULL!\n"); + return -EINVAL; + } + + if (!(pa->is_cfr_capable)) { + qdf_info("cfr is not supported on this chip\n"); + return -EINVAL; + } + + return pa->cfr_timer_enable; +} +qdf_export_symbol(ucfg_cfr_get_timer); + +int ucfg_cfr_stop_capture(struct wlan_objmgr_pdev *pdev, + struct wlan_objmgr_peer *peer) +{ + int status; + struct peer_cfr *pe; + struct pdev_cfr *pa; + + pa = wlan_objmgr_pdev_get_comp_private_obj(pdev, WLAN_UMAC_COMP_CFR); + if (pa == NULL) { + cfr_err("PDEV cfr object is NULL!\n"); + return -EINVAL; + } + + if (!(pa->is_cfr_capable)) { + qdf_info("cfr is not supported on this chip\n"); + return -EINVAL; + } + + pe = wlan_objmgr_peer_get_comp_private_obj(peer, WLAN_UMAC_COMP_CFR); + if (pe == NULL) { + cfr_err("PEER cfr object is NULL!\n"); + return -EINVAL; + } + + if ((pe->period) && (pe->request)) + status = tgt_cfr_stop_capture(pdev, peer); + else { + qdf_info("periodic cfr not started for the client\n"); + return -EINVAL; + } + + if (status == 0) { + pe->request = PEER_CFR_CAPTURE_DISABLE; + pa->cfr_current_sta_count--; + } + + return status; +} + +int ucfg_cfr_list_peers(struct wlan_objmgr_pdev *pdev) +{ + return 0; +} + +#ifdef WLAN_ENH_CFR_ENABLE + +static inline +QDF_STATUS dev_sanity_check(struct wlan_objmgr_vdev *vdev, + struct wlan_objmgr_pdev **ppdev, + struct pdev_cfr **ppcfr) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!vdev) { + cfr_err("vdev is NULL\n"); + return QDF_STATUS_E_NULL_VALUE; + } + + *ppdev = wlan_vdev_get_pdev(vdev); + + if (!*ppdev) { + cfr_err("pdev is NULL\n"); + return QDF_STATUS_E_NULL_VALUE; + } + + status = wlan_objmgr_pdev_try_get_ref(*ppdev, WLAN_CFR_ID); + if (status != QDF_STATUS_SUCCESS) { + cfr_err("Failed to get pdev reference\n"); + return status; + } + + *ppcfr = wlan_objmgr_pdev_get_comp_private_obj(*ppdev, + WLAN_UMAC_COMP_CFR); + + if (!(*ppcfr)) { + cfr_err("pdev object for CFR is null"); + wlan_objmgr_pdev_release_ref(*ppdev, WLAN_CFR_ID); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!(*ppcfr)->is_cfr_rcc_capable) { + cfr_err("cfr is not supported on this chip\n"); + wlan_objmgr_pdev_release_ref(*ppdev, WLAN_CFR_ID); + return QDF_STATUS_E_NOSUPPORT; + } + + return status; +} + +/* + * This is needed only in case of m_ta_ra_filter mode. + * If user wants to reset the group configurations to default values, + * then this handler will come into action. + * + * If user wants to reset the configurations of 0th, 1st and 3rd group, + * then the input should be : + * + * wlanconfig ath0 cfr reset_cfg 0xb + * + */ + +QDF_STATUS ucfg_cfr_set_reset_bitmap(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + pcfr->rcc_param.modified_in_curr_session |= params->reset_cfg; + tgt_cfr_default_ta_ra_cfg(pdev, &pcfr->rcc_param, + true, params->reset_cfg); + + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +/* + * This is needed only in case of m_ta_ra_filter mode. + * After providing all the group configurations, user should provide + * the information about which groups need to be enabled. + * Based on that FW will enable the configurations for CFR groups. + * If user has to enable only 0th group, then input should be : + * + * wlanconfig ath0 cfr en_cfg 0x1 + * + * Enable the bitmap from user provided configuration into cfr_rcc_param. + */ + +QDF_STATUS ucfg_cfr_set_en_bitmap(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + pcfr->rcc_param.filter_group_bitmap = params->en_cfg; + + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +/* + * Copy user provided input for ul_mu_user_mask into cfr_rcc_param. + */ + +QDF_STATUS +ucfg_cfr_set_ul_mu_user_mask(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + pcfr->rcc_param.ul_mu_user_mask_lower = params->ul_mu_user_mask_lower; + pcfr->rcc_param.ul_mu_user_mask_upper = params->ul_mu_user_mask_upper; + + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +/* + * FREEZE_TLV_DELAY_CNT_* registers are used for FREEZE TLV timeout mechanism + * in MAC side. In case MAC send FREEZE TLV to PHY too late due to + * long AST delay, PHY ucode may not handle it well or it will impact + * next frame’s normal processing, then MAC needs to drop FREEZE TLV + * sending process after reaching the threshold. + * + * This handler will copy user provided input for freeze_tlv_delay_cnt + * into cfr_rcc_param. + */ + +QDF_STATUS +ucfg_cfr_set_freeze_tlv_delay_cnt(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + pcfr->rcc_param.freeze_tlv_delay_cnt_en = + params->freeze_tlv_delay_cnt_en; + + pcfr->rcc_param.freeze_tlv_delay_cnt_thr = + params->freeze_tlv_delay_cnt_thr; + + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +/* + * Set capture interval from the provided configuration into cfr_rcc_param. + * All fixed parameters are needed to be stored into cfr_rcc_param. + */ + +QDF_STATUS +ucfg_cfr_set_capture_interval(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + pcfr->rcc_param.capture_interval = params->cap_intvl; + + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +/* + * Set capture duration from the provided configuration into cfr_rcc_param. + * All fixed parameters are needed to be stored into cfr_rcc_param. + */ + +QDF_STATUS +ucfg_cfr_set_capture_duration(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + pcfr->rcc_param.capture_duration = params->cap_dur; + + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +/* + * Copy user provided group parameters( type/ subtype of mgmt, ctrl, data ) + * into curr_cfg instance of ta_ra_cfr_cfg. + * Set valid mask for the provided configuration. + * Set modified_in_this_session for the particular group. + */ + +QDF_STATUS +ucfg_cfr_set_frame_type_subtype(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + struct ta_ra_cfr_cfg *curr_cfg = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + /* Populating current config based on user's input */ + curr_cfg = &pcfr->rcc_param.curr[params->grp_id]; + curr_cfg->mgmt_subtype_filter = params->expected_mgmt_subtype; + curr_cfg->ctrl_subtype_filter = params->expected_ctrl_subtype; + curr_cfg->data_subtype_filter = params->expected_data_subtype; + + curr_cfg->valid_mgmt_subtype = 1; + curr_cfg->valid_ctrl_subtype = 1; + curr_cfg->valid_data_subtype = 1; + + qdf_set_bit(params->grp_id, + (unsigned long *) + &pcfr->rcc_param.modified_in_curr_session); + + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +/* + * Copy user provided group parameters( BW and NSS ) + * into curr_cfg instance of ta_ra_cfr_cfg. + * Set valid mask for the provided configuration. + * Set modified_in_this_session for the particular group. + */ + +QDF_STATUS ucfg_cfr_set_bw_nss(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + struct ta_ra_cfr_cfg *curr_cfg = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + /* Populating current config based on user's input */ + curr_cfg = &pcfr->rcc_param.curr[params->grp_id]; + curr_cfg->bw = params->bw; + curr_cfg->nss = params->nss; + + curr_cfg->valid_bw_mask = 1; + curr_cfg->valid_nss_mask = 1; + + qdf_set_bit(params->grp_id, + (unsigned long *)&pcfr->rcc_param.modified_in_curr_session); + + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +/* + * Copy user provided group parameters( TA, RA, TA_MASK, RA_MASK ) + * into curr_cfg instance of ta_ra_cfr_cfg. + * Set valid mask for the provided configuration. + * Set modified_in_this_session for the particular group. + */ + +QDF_STATUS ucfg_cfr_set_tara_config(struct wlan_objmgr_vdev *vdev, + struct ieee80211_wlanconfig_cfr *params) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + struct ta_ra_cfr_cfg *curr_cfg = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + curr_cfg = &pcfr->rcc_param.curr[params->grp_id]; + qdf_mem_copy(curr_cfg->tx_addr, params->ta, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(curr_cfg->rx_addr, params->ra, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(curr_cfg->tx_addr_mask, + params->ta_mask, QDF_MAC_ADDR_SIZE); + qdf_mem_copy(curr_cfg->rx_addr_mask, + params->ra_mask, QDF_MAC_ADDR_SIZE); + + curr_cfg->valid_ta = 1; + curr_cfg->valid_ta_mask = 1; + curr_cfg->valid_ra = 1; + curr_cfg->valid_ra_mask = 1; + + qdf_set_bit(params->grp_id, + (unsigned long *) + &pcfr->rcc_param.modified_in_curr_session); + + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +static bool cfr_is_filter_enabled(struct cfr_rcc_param *rcc_param) +{ + if (rcc_param->m_directed_ftm || + rcc_param->m_all_ftm_ack || + rcc_param->m_ndpa_ndp_directed || + rcc_param->m_ndpa_ndp_all || + rcc_param->m_ta_ra_filter || + rcc_param->m_all_packet) + return true; + else + return false; +} + +QDF_STATUS ucfg_cfr_get_cfg(struct wlan_objmgr_vdev *vdev) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + struct ta_ra_cfr_cfg *glbl_cfg = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + uint8_t grp_id; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + if (!cfr_is_filter_enabled(&pcfr->rcc_param)) { + cfr_err(" All RCC modes are disabled.\n"); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + return status; + } + + cfr_err("CAPTURE MODE:\n"); + + cfr_err("m_directed_ftm is : %s\n", + pcfr->rcc_param.m_directed_ftm ? + "enabled" : "disabled"); + cfr_err("m_all_ftm_ack is : %s\n", + pcfr->rcc_param.m_all_ftm_ack ? + "enabled" : "disabled"); + cfr_err("m_ndpa_ndp_directed is: %s\n", + pcfr->rcc_param.m_ndpa_ndp_directed ? + "enabled" : "disabled"); + cfr_err("m_ndpa_ndp_all is : %s\n", + pcfr->rcc_param.m_ndpa_ndp_all ? + "enabled" : "disabled"); + cfr_err("m_ta_ra_filter is : %s\n", + pcfr->rcc_param.m_ta_ra_filter ? + "enabled" : "disabled"); + cfr_err("m_all_packet is : %s\n", + pcfr->rcc_param.m_all_packet ? + "enabled" : "disabled"); + + cfr_err("capture duration : %u usec\n", + pcfr->rcc_param.capture_duration); + cfr_err("capture interval : %u usec\n", + pcfr->rcc_param.capture_interval); + cfr_err("UL MU User mask lower : %u\n", + pcfr->rcc_param.ul_mu_user_mask_lower); + cfr_err("UL MU User mask upper : %u\n", + pcfr->rcc_param.ul_mu_user_mask_upper); + cfr_err("Freeze TLV delay count is : %s\n", + pcfr->rcc_param.freeze_tlv_delay_cnt_en ? + "enabled" : "disabled"); + cfr_err("Freeze TLV delay count threshold : %u\n", + pcfr->rcc_param.freeze_tlv_delay_cnt_thr); + cfr_err("Enabled CFG id bitmap : 0x%x\n", + pcfr->rcc_param.filter_group_bitmap); + cfr_err(" Modified cfg id bitmap : 0x%x\n", + pcfr->rcc_param.modified_in_curr_session); + + cfr_err("TARA_CONFIG details:\n"); + + for (grp_id = 0; grp_id < MAX_TA_RA_ENTRIES; grp_id++) { + glbl_cfg = &pcfr->global[grp_id]; + + cfr_err("Config ID: %d\n", grp_id); + cfr_err("Bandwidth :0x%x\n", glbl_cfg->bw); + cfr_err("NSS : 0x%x\n", glbl_cfg->nss); + cfr_err("valid_ta: %d\n", glbl_cfg->valid_ta); + cfr_err("valid_ta_mask: %d\n", glbl_cfg->valid_ta_mask); + cfr_err("valid_ra: %d\n", glbl_cfg->valid_ra); + cfr_err("valid_ra_mask: %d\n", glbl_cfg->valid_ra_mask); + cfr_err("valid_bw_mask: %d\n", glbl_cfg->valid_bw_mask); + cfr_err("valid_nss_mask: %d\n", glbl_cfg->valid_nss_mask); + cfr_err("valid_mgmt_subtype: %d\n", + glbl_cfg->valid_mgmt_subtype); + cfr_err("valid_ctrl_subtype: %d\n", + glbl_cfg->valid_ctrl_subtype); + cfr_err("valid_data_subtype: %d\n", + glbl_cfg->valid_data_subtype); + cfr_err("Mgmt subtype : 0x%x\n", + glbl_cfg->mgmt_subtype_filter); + cfr_err("CTRL subtype : 0x%x\n", + glbl_cfg->ctrl_subtype_filter); + cfr_err("Data subtype : 0x%x\n", + glbl_cfg->data_subtype_filter); + cfr_err("TX Addr : %s\n", + ether_sprintf(glbl_cfg->tx_addr)); + cfr_err("TX Addr Mask : %s\n", + ether_sprintf(glbl_cfg->tx_addr_mask)); + cfr_err("RX Addr : %s\n", + ether_sprintf(glbl_cfg->rx_addr)); + cfr_err("RX Addr Mask: %s\n", + ether_sprintf(glbl_cfg->rx_addr_mask)); + } + + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +static const char *chan_capture_status_to_str(enum chan_capture_status type) +{ + switch (type) { + case CAPTURE_IDLE: + return "CAPTURE_IDLE"; + case CAPTURE_BUSY: + return "CAPTURE_BUSY"; + case CAPTURE_ACTIVE: + return "CAPTURE_ACTIVE"; + case CAPTURE_NO_BUFFER: + return "CAPTURE_NO_BUFFER"; + default: + return "INVALID"; + } +} + +static const +char *mac_freeze_reason_to_str(enum mac_freeze_capture_reason type) +{ + switch (type) { + case FREEZE_REASON_TM: + return "FREEZE_REASON_TM"; + case FREEZE_REASON_FTM: + return "FREEZE_REASON_FTM"; + case FREEZE_REASON_ACK_RESP_TO_TM_FTM: + return "FREEZE_REASON_ACK_RESP_TO_TM_FTM"; + case FREEZE_REASON_TA_RA_TYPE_FILTER: + return "FREEZE_REASON_TA_RA_TYPE_FILTER"; + case FREEZE_REASON_NDPA_NDP: + return "FREEZE_REASON_NDPA_NDP"; + case FREEZE_REASON_ALL_PACKET: + return "FREEZE_REASON_ALL_PACKET"; + default: + return "INVALID"; + } +} + +QDF_STATUS ucfg_cfr_rcc_dump_dbg_counters(struct wlan_objmgr_vdev *vdev) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + struct wlan_objmgr_psoc *psoc = NULL; + struct cdp_cfr_rcc_stats *cfr_rcc_stats = NULL; + uint8_t stats_cnt; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + cfr_err("psoc is null!"); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + return QDF_STATUS_E_NULL_VALUE; + } + + cfr_err("total_tx_evt_cnt = %llu\n", + pcfr->total_tx_evt_cnt); + cfr_err("dbr_evt_cnt = %llu\n", + pcfr->dbr_evt_cnt); + cfr_err("rx_tlv_evt_cnt = %llu\n", + pcfr->rx_tlv_evt_cnt); + cfr_err("release_cnt = %llu\n", + pcfr->release_cnt); + cfr_err("Error cnt:\n"); + cfr_err("flush_dbr_cnt = %llu\n", + pcfr->flush_dbr_cnt); + cfr_err("invalid_dma_length_cnt = %llu\n", + pcfr->invalid_dma_length_cnt); + cfr_err("flush_timeout_dbr_cnt = %llu\n", + pcfr->flush_timeout_dbr_cnt); + cfr_err("PPDU id mismatch for same cookie:\n"); + cfr_err("clear_txrx_event = %llu\n", + pcfr->clear_txrx_event); + cfr_err("cfr_dma_aborts = %llu\n", + pcfr->cfr_dma_aborts); + + cfr_rcc_stats = qdf_mem_malloc(sizeof(struct cdp_cfr_rcc_stats)); + if (!cfr_rcc_stats) { + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + return QDF_STATUS_E_NOMEM; + } + + cdp_get_cfr_dbg_stats(wlan_psoc_get_dp_handle(psoc), + wlan_objmgr_pdev_get_pdev_id(pdev), + cfr_rcc_stats); + + cfr_err("bb_captured_channel_cnt: %llu\n", + cfr_rcc_stats->bb_captured_channel_cnt); + cfr_err("bb_captured_timeout_cnt: %llu\n", + cfr_rcc_stats->bb_captured_timeout_cnt); + cfr_err("rx_loc_info_valid_cnt: %llu\n", + cfr_rcc_stats->rx_loc_info_valid_cnt); + + cfr_err("Channel capture status:\n"); + for (stats_cnt = 0; stats_cnt < CAPTURE_MAX; stats_cnt++) { + cfr_err("%s = %llu\n", + chan_capture_status_to_str(stats_cnt), + cfr_rcc_stats->chan_capture_status[stats_cnt]); + } + + cfr_err("Freeze reason:\n"); + for (stats_cnt = 0; stats_cnt < FREEZE_REASON_MAX; stats_cnt++) { + cfr_err("%s = %llu\n", + mac_freeze_reason_to_str(stats_cnt), + cfr_rcc_stats->reason_cnt[stats_cnt]); + } + + qdf_mem_free(cfr_rcc_stats); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +QDF_STATUS ucfg_cfr_rcc_clr_dbg_counters(struct wlan_objmgr_vdev *vdev) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + struct wlan_objmgr_psoc *psoc = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + psoc = wlan_pdev_get_psoc(pdev); + if (!psoc) { + cfr_err("psoc is null!"); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + return QDF_STATUS_E_NULL_VALUE; + } + cdp_cfr_clr_dbg_stats(wlan_psoc_get_dp_handle(psoc), + wlan_objmgr_pdev_get_pdev_id(pdev)); + + pcfr->dbr_evt_cnt = 0; + pcfr->release_cnt = 0; + pcfr->total_tx_evt_cnt = 0; + pcfr->rx_tlv_evt_cnt = 0; + pcfr->flush_dbr_cnt = 0; + pcfr->flush_timeout_dbr_cnt = 0; + pcfr->invalid_dma_length_cnt = 0; + pcfr->clear_txrx_event = 0; + pcfr->cfr_dma_aborts = 0; + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +QDF_STATUS ucfg_cfr_rcc_dump_lut(struct wlan_objmgr_vdev *vdev) +{ + struct wlan_objmgr_pdev *pdev = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + if (!vdev) { + cfr_err("vdev is NULL\n"); + return QDF_STATUS_E_INVAL; + } + + pdev = wlan_vdev_get_pdev(vdev); + if (!pdev) { + cfr_err("pdev is NULL\n"); + return QDF_STATUS_E_INVAL; + } + + if (wlan_objmgr_pdev_try_get_ref(pdev, WLAN_CFR_ID) != + QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_INVAL; + } + + cfr_err("LUT table:\n"); + tgt_cfr_dump_lut_enh(pdev); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +void cfr_set_filter(struct wlan_objmgr_pdev *pdev, + bool enable, struct cdp_monitor_filter *filter_val) +{ + struct wlan_objmgr_psoc *psoc = wlan_pdev_get_psoc(pdev); + + cfr_info("pdev_id=%d\n", wlan_objmgr_pdev_get_pdev_id(pdev)); + + cdp_cfr_filter(wlan_psoc_get_dp_handle(psoc), + wlan_objmgr_pdev_get_pdev_id(pdev), + enable, + filter_val); +} + +/* + * With the initiation of commit command, this handler will be triggered. + * + * Starts the procedure of forming the TLVs. + * If Host succeeds to send WMI command to FW, after TLV processing, then it + * will save the previous CFR configurations into one instance ta_ra_cfr_cfg, + * called glbl_cfg and update the current config to default state for the + * next commit session. + * + * Finally, reset the counter (modified_in_this_session) to 0 before moving to + * next commit session. + * + */ + +QDF_STATUS ucfg_cfr_committed_rcc_config(struct wlan_objmgr_vdev *vdev) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + struct wlan_objmgr_psoc *psoc = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + struct cdp_monitor_filter filter_val = {0}; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + psoc = wlan_pdev_get_psoc(pdev); + + if (!psoc) { + cfr_err("psoc is null!"); + return QDF_STATUS_E_NULL_VALUE; + } + /* + * If capture mode is valid, then Host: + * Subscribes for PPDU status TLVs in monitor status ring. + * Sets filter type to either FP or MO, based on the capture mode. + * Starts the LUT_AGE_TIMER of 1sec. + * + * If capture mode is disabled, then Host: + * unsubscribes for PPDU status TLVs in monitor status ring. + * Sets filter type to 0. + * Stops the LUT_AGE_TIMER. + * + */ + + if (cfr_is_filter_enabled(&pcfr->rcc_param)) { + if (pcfr->rcc_param.m_all_ftm_ack) { + filter_val.mode |= MON_FILTER_PASS | + MON_FILTER_OTHER; + filter_val.fp_mgmt |= FILTER_MGMT_ACTION; + filter_val.mo_mgmt |= FILTER_MGMT_ACTION; + } + + if (pcfr->rcc_param.m_ndpa_ndp_all) { + filter_val.mode |= MON_FILTER_PASS | + MON_FILTER_OTHER; + filter_val.fp_ctrl |= FILTER_CTRL_VHT_NDP; + filter_val.mo_ctrl |= FILTER_CTRL_VHT_NDP; + } + + if (pcfr->rcc_param.m_all_packet) { + filter_val.mode |= MON_FILTER_PASS | + MON_FILTER_OTHER; + filter_val.fp_mgmt |= FILTER_MGMT_ALL; + filter_val.mo_mgmt |= FILTER_MGMT_ALL; + filter_val.fp_ctrl |= FILTER_CTRL_ALL; + filter_val.mo_ctrl |= FILTER_CTRL_ALL; + filter_val.fp_data |= FILTER_DATA_ALL; + filter_val.mo_data |= FILTER_DATA_ALL; + } + + /* + * M_TA_RA in monitor other is as intensive as M_ALL pkt + * Support only FP in M_TA_RA mode + */ + if (pcfr->rcc_param.m_ta_ra_filter) { + filter_val.mode |= MON_FILTER_PASS | + MON_FILTER_OTHER; + filter_val.fp_mgmt |= FILTER_MGMT_ALL; + filter_val.mo_mgmt |= FILTER_MGMT_ALL; + filter_val.fp_ctrl |= FILTER_CTRL_ALL; + filter_val.mo_ctrl |= FILTER_CTRL_ALL; + filter_val.fp_data |= FILTER_DATA_ALL; + filter_val.mo_data |= FILTER_DATA_ALL; + } + + if (pcfr->rcc_param.m_directed_ftm) { + filter_val.mode |= MON_FILTER_PASS; + filter_val.fp_mgmt |= FILTER_MGMT_ACTION; + } + + if (pcfr->rcc_param.m_ndpa_ndp_directed) { + filter_val.mode |= MON_FILTER_PASS; + filter_val.fp_ctrl |= FILTER_CTRL_VHT_NDP; + } + + if (!cdp_get_cfr_rcc(wlan_psoc_get_dp_handle(psoc), + wlan_objmgr_pdev_get_pdev_id(pdev))) + tgt_cfr_start_lut_age_timer(pdev); + cfr_set_filter(pdev, 1, &filter_val); + } else { + if (cdp_get_cfr_rcc(wlan_psoc_get_dp_handle(psoc), + wlan_objmgr_pdev_get_pdev_id(pdev))) + tgt_cfr_stop_lut_age_timer(pdev); + cfr_set_filter(pdev, 0, &filter_val); + } + + /* Trigger wmi to start the TLV processing. */ + status = tgt_cfr_config_rcc(pdev, &pcfr->rcc_param); + if (status == QDF_STATUS_SUCCESS) { + cfr_info("CFR commit done\n"); + /* Update global config */ + tgt_cfr_update_global_cfg(pdev); + + /* Bring curr_cfg to default state for next commit session */ + tgt_cfr_default_ta_ra_cfg(pdev, &pcfr->rcc_param, + false, MAX_RESET_CFG_ENTRY); + } else { + cfr_err("CFR commit failed\n"); + } + + pcfr->rcc_param.num_grp_tlvs = 0; + pcfr->rcc_param.modified_in_curr_session = 0; + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +/* + * This handler is used to enable / disable the capture mode. + * + */ +QDF_STATUS ucfg_cfr_set_rcc_mode(struct wlan_objmgr_vdev *vdev, + enum capture_type mode, uint8_t value) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return status; + + switch (mode) { + case RCC_DIRECTED_FTM_FILTER: + pcfr->rcc_param.m_directed_ftm = value; + break; + case RCC_ALL_FTM_ACK_FILTER: + pcfr->rcc_param.m_all_ftm_ack = value; + break; + case RCC_DIRECTED_NDPA_NDP_FILTER: + pcfr->rcc_param.m_ndpa_ndp_directed = value; + break; + case RCC_NDPA_NDP_ALL_FILTER: + pcfr->rcc_param.m_ndpa_ndp_all = value; + break; + case RCC_TA_RA_FILTER: + pcfr->rcc_param.m_ta_ra_filter = value; + break; + case RCC_ALL_PACKET_FILTER: + pcfr->rcc_param.m_all_packet = value; + break; + case RCC_DIS_ALL_MODE: + pcfr->rcc_param.m_directed_ftm = value; + pcfr->rcc_param.m_all_ftm_ack = value; + pcfr->rcc_param.m_ndpa_ndp_directed = value; + pcfr->rcc_param.m_ndpa_ndp_all = value; + pcfr->rcc_param.m_ta_ra_filter = value; + pcfr->rcc_param.m_all_packet = value; + break; + + default: + break; + } + + cfr_debug(" Capture mode set by user: 0x%x\n", value); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return status; +} + +bool ucfg_cfr_get_rcc_enabled(struct wlan_objmgr_vdev *vdev) +{ + struct pdev_cfr *pcfr = NULL; + struct wlan_objmgr_pdev *pdev = NULL; + QDF_STATUS status = QDF_STATUS_SUCCESS; + bool rcc_enabled = false; + + status = dev_sanity_check(vdev, &pdev, &pcfr); + if (status != QDF_STATUS_SUCCESS) + return false; + + rcc_enabled = cfr_is_filter_enabled(&pcfr->rcc_param); + wlan_objmgr_pdev_release_ref(pdev, WLAN_CFR_ID); + + return rcc_enabled; +} +#endif diff --git a/umac/cfr/dispatcher/src/wlan_cfr_utils_api.c b/umac/cfr/dispatcher/src/wlan_cfr_utils_api.c new file mode 100644 index 000000000000..4cb8ea2298e2 --- /dev/null +++ b/umac/cfr/dispatcher/src/wlan_cfr_utils_api.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 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 +#include +#include +#include "../../core/inc/cfr_defs_i.h" +#include +#include + +QDF_STATUS wlan_cfr_init(void) +{ + if (wlan_objmgr_register_psoc_create_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_psoc_obj_create_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + if (wlan_objmgr_register_psoc_destroy_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_psoc_obj_destroy_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + if (wlan_objmgr_register_pdev_create_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_pdev_obj_create_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + if (wlan_objmgr_register_pdev_destroy_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_pdev_obj_destroy_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + if (wlan_objmgr_register_peer_create_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_peer_obj_create_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + if (wlan_objmgr_register_peer_destroy_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_peer_obj_destroy_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cfr_deinit(void) +{ + if (wlan_objmgr_unregister_psoc_create_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_psoc_obj_create_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + if (wlan_objmgr_unregister_psoc_destroy_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_psoc_obj_destroy_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + if (wlan_objmgr_unregister_pdev_create_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_pdev_obj_create_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + if (wlan_objmgr_unregister_pdev_destroy_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_pdev_obj_destroy_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + if (wlan_objmgr_unregister_peer_create_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_peer_obj_create_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + if (wlan_objmgr_unregister_peer_destroy_handler(WLAN_UMAC_COMP_CFR, + wlan_cfr_peer_obj_destroy_handler, NULL) + != QDF_STATUS_SUCCESS) { + return QDF_STATUS_E_FAILURE; + } + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cfr_pdev_open(struct wlan_objmgr_pdev *pdev) +{ + int status; + + /* chip specific init */ + status = tgt_cfr_init_pdev(pdev); + + if (status != QDF_STATUS_SUCCESS) { + cfr_err("tgt_cfr_init_pdev failed with %d\n", status); + return QDF_STATUS_SUCCESS; + } + + /* RealyFS init */ + status = cfr_streamfs_init(pdev); + + if (status != QDF_STATUS_SUCCESS) { + cfr_err("cfr_streamfs_init failed with %d\n", status); + return QDF_STATUS_SUCCESS; + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_cfr_pdev_close(struct wlan_objmgr_pdev *pdev) +{ + int status = QDF_STATUS_SUCCESS; + /* + * DBR does not have close as of now; + * but this is getting added as part for new gerrit + * Once we have that support we will add it. + */ + status = cfr_streamfs_remove(pdev); + + return status; +} + +QDF_STATUS cfr_initialize_pdev(struct wlan_objmgr_pdev *pdev) +{ + int status = QDF_STATUS_SUCCESS; + + /* chip specific init */ + + status = tgt_cfr_init_pdev(pdev); + + if (status != QDF_STATUS_SUCCESS) + cfr_err("cfr_initialize_pdev status=%d\n", status); + + return status; +} +qdf_export_symbol(cfr_initialize_pdev); + +QDF_STATUS cfr_deinitialize_pdev(struct wlan_objmgr_pdev *pdev) +{ + int status = QDF_STATUS_SUCCESS; + + /* chip specific deinit */ + + status = tgt_cfr_deinit_pdev(pdev); + + if (status != QDF_STATUS_SUCCESS) + cfr_err("cfr_deinitialize_pdev status=%d\n", status); + + return status; +} +qdf_export_symbol(cfr_deinitialize_pdev); + +uint8_t count_set_bits(uint32_t value) +{ + uint8_t count = 0; + + while (value) { + value &= (value - 1); + count++; + } + + return count; +} + +qdf_export_symbol(count_set_bits); + +#ifdef WLAN_ENH_CFR_ENABLE +void wlan_cfr_rx_tlv_process(struct wlan_objmgr_pdev *pdev, void *nbuf) +{ + tgt_cfr_rx_tlv_process(pdev, nbuf); +} + +qdf_export_symbol(wlan_cfr_rx_tlv_process); +#endif