From fed4bfb04901bc53e8f21d8cfd8d4a151e546d11 Mon Sep 17 00:00:00 2001 From: hqu Date: Fri, 20 Sep 2019 21:06:47 +0800 Subject: [PATCH] qcacmn: Add dcs component Add dcs component to implement interference detection algorithm and dynamic channel selection frequency control. Change-Id: Ia201d77e77feb9de3aff03d6e389d4891dde118e CRs-Fixed: 2594837 --- cfg/inc/cfg_converged.h | 8 +- .../dispatcher/src/dispatcher_init_deinit.c | 86 +++ qdf/inc/qdf_types.h | 2 + qdf/linux/src/qdf_trace.c | 2 + target_if/core/src/target_if_main.c | 20 + target_if/dcs/inc/target_if_dcs.h | 70 ++ target_if/dcs/src/target_if_dcs.c | 197 +++++ umac/cmn_services/inc/wlan_cmn.h | 2 + .../obj_mgr/inc/wlan_objmgr_cmn.h | 3 + umac/dcs/core/src/wlan_dcs.c | 727 ++++++++++++++++++ umac/dcs/core/src/wlan_dcs.h | 227 ++++++ umac/dcs/dispatcher/inc/wlan_dcs_cfg.h | 309 ++++++++ .../dispatcher/inc/wlan_dcs_init_deinit_api.h | 91 +++ .../dispatcher/inc/wlan_dcs_public_structs.h | 86 +++ umac/dcs/dispatcher/inc/wlan_dcs_tgt_api.h | 50 ++ umac/dcs/dispatcher/inc/wlan_dcs_ucfg_api.h | 120 +++ .../dispatcher/src/wlan_dcs_init_deinit_api.c | 210 +++++ umac/dcs/dispatcher/src/wlan_dcs_tgt_api.c | 30 + umac/dcs/dispatcher/src/wlan_dcs_ucfg_api.c | 93 +++ .../lmac_if/inc/wlan_lmac_if_def.h | 37 + .../lmac_if/src/wlan_lmac_if.c | 23 + wmi/inc/wmi_unified_dcs_api.h | 75 ++ wmi/inc/wmi_unified_param.h | 2 + wmi/inc/wmi_unified_priv.h | 25 + wmi/src/wmi_unified_dcs_api.c | 82 ++ wmi/src/wmi_unified_dcs_tlv.c | 110 +++ wmi/src/wmi_unified_tlv.c | 8 +- 27 files changed, 2693 insertions(+), 2 deletions(-) create mode 100644 target_if/dcs/inc/target_if_dcs.h create mode 100644 target_if/dcs/src/target_if_dcs.c create mode 100644 umac/dcs/core/src/wlan_dcs.c create mode 100644 umac/dcs/core/src/wlan_dcs.h create mode 100644 umac/dcs/dispatcher/inc/wlan_dcs_cfg.h create mode 100644 umac/dcs/dispatcher/inc/wlan_dcs_init_deinit_api.h create mode 100644 umac/dcs/dispatcher/inc/wlan_dcs_public_structs.h create mode 100644 umac/dcs/dispatcher/inc/wlan_dcs_tgt_api.h create mode 100644 umac/dcs/dispatcher/inc/wlan_dcs_ucfg_api.h create mode 100644 umac/dcs/dispatcher/src/wlan_dcs_init_deinit_api.c create mode 100644 umac/dcs/dispatcher/src/wlan_dcs_tgt_api.c create mode 100644 umac/dcs/dispatcher/src/wlan_dcs_ucfg_api.c create mode 100644 wmi/inc/wmi_unified_dcs_api.h create mode 100644 wmi/src/wmi_unified_dcs_api.c create mode 100644 wmi/src/wmi_unified_dcs_tlv.c diff --git a/cfg/inc/cfg_converged.h b/cfg/inc/cfg_converged.h index 87eecad0f2..b14387902f 100644 --- a/cfg/inc/cfg_converged.h +++ b/cfg/inc/cfg_converged.h @@ -33,6 +33,11 @@ #define CFG_GREEN_AP_ALL #endif #include +#ifdef DCS_INTERFERENCE_DETECTION +#include "wlan_dcs_cfg.h" +#else +#define CFG_DCS_ALL +#endif #define CFG_CONVERGED_ALL \ CFG_SCAN_ALL \ @@ -40,7 +45,8 @@ CFG_EXTSCAN_ALL \ CFG_GREEN_AP_ALL \ CFG_SPECTRAL_ALL \ - CFG_HIF + CFG_HIF \ + CFG_DCS_ALL #endif /* __CFG_CONVERGED_H */ diff --git a/init_deinit/dispatcher/src/dispatcher_init_deinit.c b/init_deinit/dispatcher/src/dispatcher_init_deinit.c index 0781988a1c..79d3a10421 100644 --- a/init_deinit/dispatcher/src/dispatcher_init_deinit.c +++ b/init_deinit/dispatcher/src/dispatcher_init_deinit.c @@ -76,6 +76,10 @@ #include #endif +#ifdef DCS_INTERFERENCE_DETECTION +#include +#endif + /** * DOC: This file provides various init/deinit trigger point for new * components. @@ -193,6 +197,68 @@ static QDF_STATUS cp_stats_psoc_disable(struct wlan_objmgr_psoc *psoc) } #endif +#ifdef DCS_INTERFERENCE_DETECTION +static QDF_STATUS dispatcher_init_dcs(void) +{ + return wlan_dcs_init(); +} + +static QDF_STATUS dispatcher_deinit_dcs(void) +{ + return wlan_dcs_deinit(); +} + +static QDF_STATUS dcs_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return wlan_dcs_enable(psoc); +} + +static QDF_STATUS dcs_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return wlan_dcs_disable(psoc); +} + +static QDF_STATUS dcs_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return wlan_dcs_psoc_open(psoc); +} + +static QDF_STATUS dcs_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS dispatcher_init_dcs(void) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS dispatcher_deinit_dcs(void) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS dcs_psoc_enable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS dcs_psoc_disable(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS dcs_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} + +static QDF_STATUS dcs_psoc_close(struct wlan_objmgr_psoc *psoc) +{ + return QDF_STATUS_SUCCESS; +} +#endif + #if defined QCA_SUPPORT_SON && QCA_SUPPORT_SON >= 1 static QDF_STATUS dispatcher_init_son(void) { @@ -775,6 +841,9 @@ QDF_STATUS dispatcher_init(void) if (QDF_STATUS_SUCCESS != dispatcher_init_cp_stats()) goto cp_stats_init_fail; + if (QDF_STATUS_SUCCESS != dispatcher_init_dcs()) + goto dcs_init_fail; + if (QDF_STATUS_SUCCESS != dispatcher_init_atf()) goto atf_init_fail; @@ -866,6 +935,8 @@ wifi_pos_init_fail: sa_api_init_fail: dispatcher_deinit_atf(); atf_init_fail: + dispatcher_deinit_dcs(); +dcs_init_fail: dispatcher_deinit_cp_stats(); cp_stats_init_fail: dispatcher_deinit_crypto(); @@ -924,6 +995,8 @@ QDF_STATUS dispatcher_deinit(void) QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_deinit_cp_stats()); + QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_deinit_dcs()); + QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_deinit_crypto()); QDF_BUG(QDF_STATUS_SUCCESS == wlan_serialization_deinit()); @@ -982,8 +1055,13 @@ QDF_STATUS dispatcher_psoc_open(struct wlan_objmgr_psoc *psoc) if (QDF_STATUS_SUCCESS != dispatcher_coex_psoc_open(psoc)) goto coex_psoc_open_fail; + if (QDF_STATUS_SUCCESS != dcs_psoc_open(psoc)) + goto dcs_psoc_open_fail; + return QDF_STATUS_SUCCESS; +dcs_psoc_open_fail: + dispatcher_coex_psoc_close(psoc); coex_psoc_open_fail: dispatcher_ftm_psoc_close(psoc); ftm_psoc_open_fail: @@ -1006,6 +1084,8 @@ qdf_export_symbol(dispatcher_psoc_open); QDF_STATUS dispatcher_psoc_close(struct wlan_objmgr_psoc *psoc) { + QDF_BUG(QDF_STATUS_SUCCESS == dcs_psoc_close(psoc)); + QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_coex_psoc_close(psoc)); QDF_BUG(QDF_STATUS_SUCCESS == dispatcher_ftm_psoc_close(psoc)); @@ -1040,6 +1120,9 @@ QDF_STATUS dispatcher_psoc_enable(struct wlan_objmgr_psoc *psoc) if (QDF_STATUS_SUCCESS != cp_stats_psoc_enable(psoc)) goto cp_stats_psoc_enable_fail; + if (QDF_STATUS_SUCCESS != dcs_psoc_enable(psoc)) + goto dcs_psoc_enable_fail; + if (QDF_STATUS_SUCCESS != atf_psoc_enable(psoc)) goto atf_psoc_enable_fail; @@ -1071,6 +1154,8 @@ wifi_dfs_psoc_enable_fail: wifi_pos_psoc_enable_fail: atf_psoc_disable(psoc); atf_psoc_enable_fail: + dcs_psoc_disable(psoc); +dcs_psoc_enable_fail: cp_stats_psoc_disable(psoc); cp_stats_psoc_enable_fail: sa_api_psoc_disable(psoc); @@ -1126,6 +1211,7 @@ QDF_STATUS dispatcher_pdev_open(struct wlan_objmgr_pdev *pdev) if (QDF_STATUS_SUCCESS != wlan_mgmt_txrx_pdev_open(pdev)) goto mgmt_txrx_pdev_open_fail; + if (QDF_IS_STATUS_ERROR(dispatcher_green_ap_pdev_open(pdev))) goto green_ap_pdev_open_fail; diff --git a/qdf/inc/qdf_types.h b/qdf/inc/qdf_types.h index d8654670ba..fc7ef4dd02 100644 --- a/qdf/inc/qdf_types.h +++ b/qdf/inc/qdf_types.h @@ -381,6 +381,7 @@ typedef bool (*qdf_irqlocked_func_t)(void *); * @QDF_MODULE_ID_FTM_TIME_SYNC: FTM Time sync module ID * @QDF_MODULE_ID_PKT_CAPTURE: PACKET CAPTURE module ID * @QDF_MODULE_ID_MON_FILTER: Monitor filter related config module ID + * @QDF_MODULE_ID_DCS: DCS module ID * @QDF_MODULE_ID_ANY: anything * @QDF_MODULE_ID_MAX: Max place holder module ID */ @@ -503,6 +504,7 @@ typedef enum { QDF_MODULE_ID_FTM_TIME_SYNC, QDF_MODULE_ID_PKT_CAPTURE, QDF_MODULE_ID_MON_FILTER, + QDF_MODULE_ID_DCS, QDF_MODULE_ID_ANY, QDF_MODULE_ID_MAX, } QDF_MODULE_ID; diff --git a/qdf/linux/src/qdf_trace.c b/qdf/linux/src/qdf_trace.c index 35b7d3c11c..3014f482fa 100644 --- a/qdf/linux/src/qdf_trace.c +++ b/qdf/linux/src/qdf_trace.c @@ -3080,6 +3080,7 @@ struct category_name_info g_qdf_category_name[MAX_SUPPORTED_CATEGORY] = { [QDF_MODULE_ID_CONFIG] = {"CONFIG"}, [QDF_MODULE_ID_IPA] = {"IPA"}, [QDF_MODULE_ID_CP_STATS] = {"CP_STATS"}, + [QDF_MODULE_ID_DCS] = {"DCS"}, [QDF_MODULE_ID_ACTION_OUI] = {"action_oui"}, [QDF_MODULE_ID_TARGET] = {"TARGET"}, [QDF_MODULE_ID_MBSSIE] = {"MBSSIE"}, @@ -3543,6 +3544,7 @@ static void set_default_trace_levels(struct category_info *cinfo) [QDF_MODULE_ID_IPA] = QDF_TRACE_LEVEL_NONE, [QDF_MODULE_ID_ACTION_OUI] = QDF_TRACE_LEVEL_NONE, [QDF_MODULE_ID_CP_STATS] = QDF_TRACE_LEVEL_ERROR, + [QDF_MODULE_ID_DCS] = QDF_TRACE_LEVEL_ERROR, [QDF_MODULE_ID_MBSSIE] = QDF_TRACE_LEVEL_INFO, [QDF_MODULE_ID_FWOL] = QDF_TRACE_LEVEL_NONE, [QDF_MODULE_ID_SM_ENGINE] = QDF_TRACE_LEVEL_ERROR, diff --git a/target_if/core/src/target_if_main.c b/target_if/core/src/target_if_main.c index a37f721f87..71fe908a20 100644 --- a/target_if/core/src/target_if_main.c +++ b/target_if/core/src/target_if_main.c @@ -84,6 +84,10 @@ #include #endif +#ifdef DCS_INTERFERENCE_DETECTION +#include +#endif + static struct target_if_ctx *g_target_if_ctx; struct target_if_ctx *target_if_get_ctx() @@ -399,6 +403,20 @@ target_if_cp_stats_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops) return target_if_cp_stats_register_tx_ops(tx_ops); } +#ifdef DCS_INTERFERENCE_DETECTION +static QDF_STATUS +target_if_dcs_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops) +{ + return target_if_dcs_register_tx_ops(tx_ops); +} +#else +static QDF_STATUS +target_if_dcs_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops) +{ + return QDF_STATUS_SUCCESS; +} +#endif + static QDF_STATUS target_if_vdev_mgr_tx_ops_register(struct wlan_lmac_if_tx_ops *tx_ops) { @@ -455,6 +473,8 @@ QDF_STATUS target_if_register_umac_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) target_if_cp_stats_tx_ops_register(tx_ops); + target_if_dcs_tx_ops_register(tx_ops); + target_if_crypto_tx_ops_register(tx_ops); target_if_vdev_mgr_tx_ops_register(tx_ops); diff --git a/target_if/dcs/inc/target_if_dcs.h b/target_if/dcs/inc/target_if_dcs.h new file mode 100644 index 0000000000..9520878f26 --- /dev/null +++ b/target_if/dcs/inc/target_if_dcs.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: target_if_dcs.h + * + * This header file provide declarations required for Rx and Tx events from + * firmware + */ + +#ifndef __TARGET_IF_DCS_H__ +#define __TARGET_IF_DCS_H__ + +#include +#include + +/** + * target_if_dcs_get_rx_ops() - get rx ops + * @tx_ops: pointer to target_if tx ops + * + * API to retrieve the dcs rx ops from the psoc context + * + * Return: pointer to rx ops + */ +static inline struct wlan_target_if_dcs_rx_ops * +target_if_dcs_get_rx_ops(struct wlan_objmgr_psoc *psoc) +{ + return &psoc->soc_cb.rx_ops.dcs_rx_ops; +} + +/** + * target_if_dcs_get_tx_ops() - get tx ops + * @tx_ops: pointer to target_if tx ops + * + * API to retrieve the dcs tx ops from the psoc context + * + * Return: pointer to tx ops + */ +static inline struct wlan_target_if_dcs_tx_ops * +target_if_dcs_get_tx_ops(struct wlan_objmgr_psoc *psoc) +{ + return &psoc->soc_cb.tx_ops.dcs_tx_ops; +} + +/** + * target_if_dcs_register_tx_ops() - register dcs target_if tx ops functions + * @tx_ops: pointer to target_if tx ops + * + * API to register dcs tx ops + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS +target_if_dcs_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops); + +#endif /* __TARGET_IF_DCS_H__ */ + diff --git a/target_if/dcs/src/target_if_dcs.c b/target_if/dcs/src/target_if_dcs.c new file mode 100644 index 0000000000..16a4274423 --- /dev/null +++ b/target_if/dcs/src/target_if_dcs.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: target_if_dcs.c + * + * This file provide definition for APIs registered through lmac Tx Ops + */ + +#include +#include +#include +#include +#include "wlan_dcs_tgt_api.h" +#include "target_if_dcs.h" + +/** + * target_if_dcs_interference_event_handler() - function to handle dcs event + * from firmware. + * @scn: scn handle + * @data: data buffer for event + * @datalen: data length + * + * Return: status of operation. + */ +static int target_if_dcs_interference_event_handler(ol_scn_t scn, + uint8_t *data, + uint32_t datalen) +{ + QDF_STATUS status; + struct dcs_stats_event ev; + struct wlan_objmgr_psoc *psoc; + struct wmi_unified *wmi_handle; + struct wlan_target_if_dcs_rx_ops *rx_ops; + + if (!scn || !data) { + target_if_err("scn: 0x%pK, data: 0x%pK", scn, data); + return -EINVAL; + } + psoc = target_if_get_psoc_from_scn_hdl(scn); + if (!psoc) { + target_if_err("null psoc"); + return -EINVAL; + } + + rx_ops = target_if_dcs_get_rx_ops(psoc); + if (!rx_ops || !rx_ops->process_dcs_event) { + target_if_err("callback not registered"); + return -EINVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return -EINVAL; + } + + if (wmi_extract_dcs_interference_type(wmi_handle, data, + &ev.dcs_param) != + QDF_STATUS_SUCCESS) { + target_if_err("Unable to extract dcs interference type"); + return -EINVAL; + } + + if (wmi_extract_dcs_im_tgt_stats(wmi_handle, data, &ev.wlan_stat) != + QDF_STATUS_SUCCESS) { + target_if_err("Unable to extract WLAN IM stats"); + return -EINVAL; + } + + status = rx_ops->process_dcs_event(psoc, &ev); + + return qdf_status_to_os_return(status); +} + +static QDF_STATUS +target_if_dcs_register_event_handler(struct wlan_objmgr_psoc *psoc) +{ + int ret_val; + struct wmi_unified *wmi_handle; + + if (!psoc) { + target_if_err("PSOC is NULL!"); + return QDF_STATUS_E_NULL_VALUE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + + ret_val = wmi_unified_register_event_handler( + wmi_handle, + wmi_dcs_interference_event_id, + target_if_dcs_interference_event_handler, + WMI_RX_WORK_CTX); + if (ret_val) + target_if_err("Failed to register dcs interference event cb"); + + return qdf_status_from_os_return(ret_val); +} + +static QDF_STATUS +target_if_dcs_unregister_event_handler(struct wlan_objmgr_psoc *psoc) +{ + struct wmi_unified *wmi_handle; + + if (!psoc) { + target_if_err("PSOC is NULL!"); + return QDF_STATUS_E_INVAL; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("wmi_handle is null"); + return QDF_STATUS_E_INVAL; + } + wmi_unified_unregister_event_handler(wmi_handle, + wmi_dcs_interference_event_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_dcs_cmd_send() - Send WMI command for dcs requests + * @psoc: psoc pointer + * @pdev_id: pdev_id + * @is_target_pdev_id: pdev_id is target pdev_id or not + * @dcs_enable: dcs enable or not + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +static QDF_STATUS +target_if_dcs_cmd_send(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id, + bool is_target_pdev_id, uint32_t dcs_enable) +{ + QDF_STATUS ret; + struct wmi_unified *wmi_handle; + + if (!psoc) { + target_if_err("null psoc"); + return QDF_STATUS_E_FAILURE; + } + + wmi_handle = get_wmi_unified_hdl_from_psoc(psoc); + if (!wmi_handle) { + target_if_err("null handle"); + return QDF_STATUS_E_FAILURE; + } + + ret = wmi_send_dcs_pdev_param(wmi_handle, pdev_id, + is_target_pdev_id, dcs_enable); + if (QDF_IS_STATUS_ERROR(ret)) + target_if_err("wmi dcs cmd send failed, ret: %d", ret); + + return ret; +} + +QDF_STATUS +target_if_dcs_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) +{ + struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; + + if (!tx_ops) { + target_if_err("lmac tx ops is NULL!"); + return QDF_STATUS_E_INVAL; + } + + dcs_tx_ops = &tx_ops->dcs_tx_ops; + if (!dcs_tx_ops) { + target_if_err("lmac tx ops is NULL!"); + return QDF_STATUS_E_FAILURE; + } + + dcs_tx_ops->dcs_attach = + target_if_dcs_register_event_handler; + dcs_tx_ops->dcs_detach = + target_if_dcs_unregister_event_handler; + dcs_tx_ops->dcs_cmd_send = target_if_dcs_cmd_send; + + return QDF_STATUS_SUCCESS; +} + diff --git a/umac/cmn_services/inc/wlan_cmn.h b/umac/cmn_services/inc/wlan_cmn.h index dff1998d92..96b1e98039 100644 --- a/umac/cmn_services/inc/wlan_cmn.h +++ b/umac/cmn_services/inc/wlan_cmn.h @@ -275,6 +275,7 @@ * @WLAN_UMAC_COMP_COEX: Coex config component * @WLAN_UMAC_COMP_FTM_TIME_SYNC: WLAN FTM TIMESYNC * @WLAN_UMAC_COMP_PKT_CAPTURE: Packet capture component + * @WLAN_UMAC_COMP_DCS: DCS * @WLAN_UMAC_COMP_ID_MAX: Maximum components in UMAC * * This id is static. @@ -317,6 +318,7 @@ enum wlan_umac_comp_id { WLAN_UMAC_COMP_COEX = 33, WLAN_UMAC_COMP_FTM_TIME_SYNC = 34, WLAN_UMAC_COMP_PKT_CAPTURE = 35, + WLAN_UMAC_COMP_DCS = 36, WLAN_UMAC_COMP_ID_MAX, }; diff --git a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h index 064098c500..8109635317 100644 --- a/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h +++ b/umac/cmn_services/obj_mgr/inc/wlan_objmgr_cmn.h @@ -262,6 +262,7 @@ typedef void (*wlan_objmgr_peer_status_handler)( * @WLAN_PSOC_TARGET_IF_ID PSOC related target_if operations * @FTM_TIME_SYNC_ID: ftm time sync operations * @WLAN_PKT_CAPTURE_ID Packet capture operations + * @WLAN_DCS_ID: DCS operations * @WLAN_REF_ID_MAX: Max id used to generate ref count tracking array */ /* New value added to the enum must also be reflected in function @@ -343,6 +344,7 @@ typedef enum { WLAN_PSOC_TARGET_IF_ID = 72, FTM_TIME_SYNC_ID = 73, WLAN_PKT_CAPTURE_ID = 74, + WLAN_DCS_ID = 75, WLAN_REF_ID_MAX, } wlan_objmgr_ref_dbgid; @@ -428,6 +430,7 @@ static inline char *string_from_dbgid(wlan_objmgr_ref_dbgid id) "WLAN_MISC_ID", "WLAN_FWOL_NB_ID", "WLAN_FWOL_SB_ID", + "WLAN_DCS_ID", "WLAN_REF_ID_MAX"}; return (char *)strings[id]; diff --git a/umac/dcs/core/src/wlan_dcs.c b/umac/dcs/core/src/wlan_dcs.c new file mode 100644 index 0000000000..7f485a3ee9 --- /dev/null +++ b/umac/dcs/core/src/wlan_dcs.c @@ -0,0 +1,727 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_dcs.c + * + * This file provide definitions for following: + * - (de)register to WMI events for psoc enable + * - send dcs wmi command + * - dcs algorithm handling + */ + +#include +#include "wlan_dcs.h" + +struct dcs_pdev_priv_obj * +wlan_dcs_get_pdev_private_obj(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id) +{ + struct dcs_psoc_priv_obj *dcs_psoc_obj; + struct dcs_pdev_priv_obj *dcs_pdev_priv = NULL; + + if (!psoc) { + dcs_err("psoc is null"); + goto end; + } + + dcs_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj( + psoc, + WLAN_UMAC_COMP_DCS); + if (!dcs_psoc_obj) { + dcs_err("dcs psoc object is null"); + goto end; + } + + if (pdev_id >= WLAN_UMAC_MAX_PDEVS) { + dcs_err("invalid pdev_id: %u", pdev_id); + goto end; + } + + dcs_pdev_priv = &dcs_psoc_obj->dcs_pdev_priv[pdev_id]; +end: + + return dcs_pdev_priv; +} + +QDF_STATUS wlan_dcs_attach(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; + + if (!psoc) { + dcs_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); + if (!dcs_tx_ops) { + dcs_err("tx_ops is null!"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!dcs_tx_ops->dcs_attach) { + dcs_err("dcs_attach function is null!"); + return QDF_STATUS_E_NULL_VALUE; + } + + return dcs_tx_ops->dcs_attach(psoc); +} + +QDF_STATUS wlan_dcs_detach(struct wlan_objmgr_psoc *psoc) +{ + struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; + + if (!psoc) { + dcs_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); + if (!dcs_tx_ops) { + dcs_err("tx_ops is null!"); + return QDF_STATUS_E_NULL_VALUE; + } + + if (!dcs_tx_ops->dcs_detach) { + dcs_err("dcs_detach function is null!"); + return QDF_STATUS_E_NULL_VALUE; + } + + return dcs_tx_ops->dcs_detach(psoc); +} + +QDF_STATUS wlan_dcs_cmd_send(struct wlan_objmgr_psoc *psoc, + uint32_t pdev_id, + bool is_target_pdev_id) +{ + struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; + struct dcs_pdev_priv_obj *dcs_pdev_priv; + uint32_t dcs_enable; + + if (!psoc) { + dcs_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); + if (!dcs_pdev_priv) { + dcs_err("dcs pdev private object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + dcs_enable = dcs_pdev_priv->dcs_host_params.dcs_enable & + dcs_pdev_priv->dcs_host_params.dcs_enable_cfg; + dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); + + if (dcs_tx_ops->dcs_cmd_send) { + dcs_info("dcs_enable: %u, pdev_id: %u", dcs_enable, pdev_id); + return dcs_tx_ops->dcs_cmd_send(psoc, + pdev_id, + is_target_pdev_id, + dcs_enable); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_dcs_disable_cmd_send() - send dcs disable command to target_if layer + * @psoc: psoc pointer + * @pdev_id: pdev_id + * @is_target_pdev_id: pdev_id is target id or not + * + * The function gets called to send dcs disable command to FW + * + * return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS wlan_dcs_disable_cmd_send(struct wlan_objmgr_psoc *psoc, + uint32_t pdev_id, + bool is_target_pdev_id) +{ + struct wlan_target_if_dcs_tx_ops *dcs_tx_ops; + struct dcs_pdev_priv_obj *dcs_pdev_priv; + + if (!psoc) { + dcs_err("psoc is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); + if (!dcs_pdev_priv) { + dcs_err("dcs pdev private object is null"); + return QDF_STATUS_E_NULL_VALUE; + } + + dcs_tx_ops = target_if_dcs_get_tx_ops(psoc); + if (dcs_tx_ops->dcs_cmd_send) { + dcs_info("dcs_enable: %u, pdev_id: %u", 0, pdev_id); + return dcs_tx_ops->dcs_cmd_send(psoc, + pdev_id, + is_target_pdev_id, + 0); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * wlan_dcs_im_copy_stats() - dcs target interference mitigation statistics copy + * @prev_stats: previous statistics pointer + * @curr_stats: current statistics pointer + * + * Return: None + */ +static inline void +wlan_dcs_im_copy_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats, + struct wlan_host_dcs_im_tgt_stats *curr_stats) +{ + if (!prev_stats || !curr_stats) { + dcs_err("previous or current stats is null"); + return; + } + + /* + * Right now no other actions are required beyond memcopy, + * if required the rest of the code would follow. + */ + qdf_mem_copy(prev_stats, curr_stats, + sizeof(struct wlan_host_dcs_im_tgt_stats)); +} + +/** + * wlan_dcs_im_print_stats() - print current/previous dcs target im statistics + * @prev_stats: previous statistics pointer + * @curr_stats: current statistics pointer + * + * Return: None + */ +static void +wlan_dcs_im_print_stats(struct wlan_host_dcs_im_tgt_stats *prev_stats, + struct wlan_host_dcs_im_tgt_stats *curr_stats) +{ + if (!prev_stats || !curr_stats) { + dcs_err("previous or current stats is null"); + return; + } + + /* Debug, dump all received stats first */ + dcs_debug("tgt_curr/tsf: %u", curr_stats->reg_tsf32); + dcs_debug("tgt_curr/last_ack_rssi: %u", curr_stats->last_ack_rssi); + dcs_debug("tgt_curr/tx_waste_time: %u", curr_stats->tx_waste_time); + dcs_debug("tgt_curr/dcs_rx_time: %u", curr_stats->rx_time); + dcs_debug("tgt_curr/listen_time: %u", + curr_stats->mib_stats.listen_time); + dcs_debug("tgt_curr/tx_frame_cnt: %u", + curr_stats->mib_stats.reg_tx_frame_cnt); + dcs_debug("tgt_curr/rx_frame_cnt: %u", + curr_stats->mib_stats.reg_rx_frame_cnt); + dcs_debug("tgt_curr/rxclr_cnt: %u", + curr_stats->mib_stats.reg_rxclr_cnt); + dcs_debug("tgt_curr/reg_cycle_cnt: %u", + curr_stats->mib_stats.reg_cycle_cnt); + dcs_debug("tgt_curr/rxclr_ext_cnt: %u", + curr_stats->mib_stats.reg_rxclr_ext_cnt); + dcs_debug("tgt_curr/ofdm_phyerr_cnt: %u", + curr_stats->mib_stats.reg_ofdm_phyerr_cnt); + dcs_debug("tgt_curr/cck_phyerr_cnt: %u", + curr_stats->mib_stats.reg_cck_phyerr_cnt); + + dcs_debug("tgt_prev/tsf: %u", prev_stats->reg_tsf32); + dcs_debug("tgt_prev/last_ack_rssi: %u", prev_stats->last_ack_rssi); + dcs_debug("tgt_prev/tx_waste_time: %u", prev_stats->tx_waste_time); + dcs_debug("tgt_prev/rx_time: %u", prev_stats->rx_time); + dcs_debug("tgt_prev/listen_time: %u", + prev_stats->mib_stats.listen_time); + dcs_debug("tgt_prev/tx_frame_cnt: %u", + prev_stats->mib_stats.reg_tx_frame_cnt); + dcs_debug("tgt_prev/rx_frame_cnt: %u", + prev_stats->mib_stats.reg_rx_frame_cnt); + dcs_debug("tgt_prev/rxclr_cnt: %u", + prev_stats->mib_stats.reg_rxclr_cnt); + dcs_debug("tgt_prev/reg_cycle_cnt: %u", + prev_stats->mib_stats.reg_cycle_cnt); + dcs_debug("tgt_prev/rxclr_ext_cnt: %u", + prev_stats->mib_stats.reg_rxclr_ext_cnt); + dcs_debug("tgt_prev/ofdm_phyerr_cnt: %u", + prev_stats->mib_stats.reg_ofdm_phyerr_cnt); + dcs_debug("tgt_prev/cck_phyerr_cnt: %u", + prev_stats->mib_stats.reg_cck_phyerr_cnt); +} + +/** + * wlan_dcs_wlan_interference_process() - dcs detection algorithm handling + * @curr_stats: current target im stats pointer + * @dcs_pdev_priv: dcs pdev priv pointer + * + * Return: true or false means start dcs callback handler or not + */ +static bool +wlan_dcs_wlan_interference_process( + struct wlan_host_dcs_im_tgt_stats *curr_stats, + struct dcs_pdev_priv_obj *dcs_pdev_priv) +{ + struct wlan_host_dcs_im_tgt_stats *prev_stats; + struct pdev_dcs_params dcs_host_params; + struct pdev_dcs_im_stats dcs_im_stats; + bool start_dcs_cbk_handler = false; + + uint32_t reg_tsf_delta = 0; + uint32_t rxclr_delta = 0; + uint32_t rxclr_ext_delta = 0; + uint32_t cycle_count_delta = 0; + uint32_t tx_frame_delta = 0; + uint32_t rx_frame_delta = 0; + uint32_t reg_total_cu = 0; + uint32_t reg_tx_cu = 0; + uint32_t reg_rx_cu = 0; + uint32_t reg_unused_cu = 0; + uint32_t rx_time_cu = 0; + uint32_t reg_ofdm_phyerr_delta = 0; + uint32_t reg_cck_phyerr_delta = 0; + uint32_t reg_ofdm_phyerr_cu = 0; + uint32_t ofdm_phy_err_rate = 0; + uint32_t cck_phy_err_rate = 0; + uint32_t max_phy_err_rate = 0; + uint32_t max_phy_err_count = 0; + uint32_t total_wasted_cu = 0; + uint32_t wasted_tx_cu = 0; + uint32_t tx_err = 0; + uint32_t too_many_phy_errors = 0; + + if (!curr_stats) { + dcs_err("curr_stats is NULL"); + goto end; + } + + if (!dcs_pdev_priv) { + dcs_err("dcs pdev private object is NULL"); + goto end; + } + + dcs_host_params = dcs_pdev_priv->dcs_host_params; + dcs_im_stats = dcs_pdev_priv->dcs_im_stats; + prev_stats = &dcs_pdev_priv->dcs_im_stats.prev_dcs_im_stats; + + if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) + wlan_dcs_im_print_stats(prev_stats, curr_stats); + + /* + * Counters would have wrapped. Ideally we should be able to figure this + * out, but we never know how many times counters wrapped, just ignore. + */ + if ((curr_stats->mib_stats.listen_time <= 0) || + (curr_stats->reg_tsf32 <= prev_stats->reg_tsf32)) { + if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) + dcs_debug("ignoring due to negative TSF value"); + + /* Copy the current stats to previous stats for next run */ + wlan_dcs_im_copy_stats(prev_stats, curr_stats); + + goto end; + } + + reg_tsf_delta = curr_stats->reg_tsf32 - prev_stats->reg_tsf32; + + /* + * Do nothing if current stats are not seeming good, probably + * a reset happened on chip, force cleared + */ + if (prev_stats->mib_stats.reg_rxclr_cnt > + curr_stats->mib_stats.reg_rxclr_cnt) { + if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) + dcs_debug("ignoring due to negative rxclr count"); + + /* Copy the current stats to previous stats for next run */ + wlan_dcs_im_copy_stats(prev_stats, curr_stats); + + goto end; + } + + rxclr_delta = curr_stats->mib_stats.reg_rxclr_cnt - + prev_stats->mib_stats.reg_rxclr_cnt; + rxclr_ext_delta = curr_stats->mib_stats.reg_rxclr_ext_cnt - + prev_stats->mib_stats.reg_rxclr_ext_cnt; + tx_frame_delta = curr_stats->mib_stats.reg_tx_frame_cnt - + prev_stats->mib_stats.reg_tx_frame_cnt; + + rx_frame_delta = curr_stats->mib_stats.reg_rx_frame_cnt - + prev_stats->mib_stats.reg_rx_frame_cnt; + + cycle_count_delta = curr_stats->mib_stats.reg_cycle_cnt - + prev_stats->mib_stats.reg_cycle_cnt; + + if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) + dcs_debug("rxclr_delta: %u, rxclr_ext_delta: %u, tx_frame_delta: %u, rx_frame_delta: %u, cycle_count_delta: %u", + rxclr_delta, rxclr_ext_delta, + tx_frame_delta, rx_frame_delta, cycle_count_delta); + + if (0 == (cycle_count_delta >> 8)) { + wlan_dcs_im_copy_stats(prev_stats, curr_stats); + if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) + dcs_debug("cycle count NULL --Investigate--"); + + goto end; + } + + /* + * Total channel utiliztaion is the amount of time RXCLR is + * counted. RXCLR is counted, when 'RX is NOT clear', please + * refer to mac documentation. It means either TX or RX is ON + * + * Why shift by 8 ? after multiplication it could overflow. At one + * second rate, neither cycle_count_celta nor the tsf_delta would be + * zero after shift by 8 bits + */ + reg_total_cu = ((rxclr_delta >> 8) * 100) / (cycle_count_delta >> 8); + reg_tx_cu = ((tx_frame_delta >> 8) * 100) / (cycle_count_delta >> 8); + reg_rx_cu = ((rx_frame_delta >> 8) * 100) / (cycle_count_delta >> 8); + rx_time_cu = ((curr_stats->rx_time >> 8) * 100) / (reg_tsf_delta >> 8); + + /* + * Amount of the time AP received cannot go higher than the receive + * cycle count delta. If at all it is, there should have been a + * computation error, ceil it to receive_cycle_count_diff + */ + if (rx_time_cu > reg_rx_cu) + rx_time_cu = reg_rx_cu; + + if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) + dcs_debug("reg_total_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u, rx_time_cu: %u", + reg_total_cu, reg_tx_cu, reg_rx_cu, rx_time_cu); + + /* + * Unusable channel utilization is amount of time that we + * spent in backoff or waiting for other transmit/receive to + * complete. If there is interference it is more likely that + * we overshoot the limit. In case of multiple stations, we + * still see increased channel utilization. This assumption may + * not be true for the VOW scenario where either multicast or + * unicast-UDP is used ( mixed traffic would still cause high + * channel utilization). + */ + wasted_tx_cu = ((curr_stats->tx_waste_time >> 8) * 100) / + (reg_tsf_delta >> 8); + + /* + * Transmit channel utilization cannot go higher than the amount of time + * wasted, if so cap the wastage to transmit channel utillzation. This + * could happen to compution error. + */ + if (reg_tx_cu < wasted_tx_cu) + wasted_tx_cu = reg_tx_cu; + + tx_err = (reg_tx_cu && wasted_tx_cu) ? + (wasted_tx_cu * 100) / reg_tx_cu : 0; + + /* + * The below actually gives amount of time we are not using, or the + * interferer is active. + * rx_time_cu is what computed receive time *NOT* rx_cycle_count + * rx_cycle_count is our receive+interferer's transmit + * un-used is really total_cycle_counts - + * (our_rx_time(rx_time_cu) + our_receive_time) + */ + reg_unused_cu = (reg_total_cu >= (reg_tx_cu + rx_time_cu)) ? + (reg_total_cu - (reg_tx_cu + rx_time_cu)) : 0; + + /* If any retransmissions are there, count them as wastage */ + total_wasted_cu = reg_unused_cu + wasted_tx_cu; + + /* Check ofdm and cck errors */ + if (unlikely(curr_stats->mib_stats.reg_ofdm_phyerr_cnt < + prev_stats->mib_stats.reg_ofdm_phyerr_cnt)) + reg_ofdm_phyerr_delta = + curr_stats->mib_stats.reg_ofdm_phyerr_cnt; + else + reg_ofdm_phyerr_delta = + curr_stats->mib_stats.reg_ofdm_phyerr_cnt - + prev_stats->mib_stats.reg_ofdm_phyerr_cnt; + + if (unlikely(curr_stats->mib_stats.reg_cck_phyerr_cnt < + prev_stats->mib_stats.reg_cck_phyerr_cnt)) + reg_cck_phyerr_delta = curr_stats->mib_stats.reg_cck_phyerr_cnt; + else + reg_cck_phyerr_delta = + curr_stats->mib_stats.reg_cck_phyerr_cnt - + prev_stats->mib_stats.reg_cck_phyerr_cnt; + + /* + * Add the influence of ofdm phy errors to the wasted channel + * utillization, this computed through time wasted in errors + */ + reg_ofdm_phyerr_cu = reg_ofdm_phyerr_delta * + dcs_host_params.phy_err_penalty; + total_wasted_cu += + (reg_ofdm_phyerr_cu > 0) ? + (((reg_ofdm_phyerr_cu >> 8) * 100) / (reg_tsf_delta >> 8)) : 0; + + ofdm_phy_err_rate = (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 1000) / + curr_stats->mib_stats.listen_time; + cck_phy_err_rate = (curr_stats->mib_stats.reg_cck_phyerr_cnt * 1000) / + curr_stats->mib_stats.listen_time; + + if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) { + dcs_debug("reg_unused_cu: %u, reg_ofdm_phyerr_delta: %u, reg_cck_phyerr_delta: %u, reg_ofdm_phyerr_cu: %u", + reg_unused_cu, reg_ofdm_phyerr_delta, + reg_cck_phyerr_delta, reg_ofdm_phyerr_cu); + dcs_debug("total_wasted_cu: %u, ofdm_phy_err_rate: %u, cck_phy_err_rate: %u", + total_wasted_cu, ofdm_phy_err_rate, cck_phy_err_rate); + dcs_debug("new_unused_cu: %u, reg_ofdm_phy_error_cu: %u", + reg_unused_cu, + (curr_stats->mib_stats.reg_ofdm_phyerr_cnt * 100) / + curr_stats->mib_stats.listen_time); + } + + /* Check if the error rates are higher than the thresholds */ + max_phy_err_rate = QDF_MAX(ofdm_phy_err_rate, cck_phy_err_rate); + + max_phy_err_count = QDF_MAX(curr_stats->mib_stats.reg_ofdm_phyerr_cnt, + curr_stats->mib_stats.reg_cck_phyerr_cnt); + + if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) + dcs_debug("max_phy_err_rate: %u, max_phy_err_count: %u", + max_phy_err_rate, max_phy_err_count); + + if (((max_phy_err_rate >= dcs_host_params.phy_err_threshold) && + (max_phy_err_count > dcs_host_params.phy_err_threshold)) || + (curr_stats->phyerr_cnt > dcs_host_params.radar_err_threshold)) + too_many_phy_errors = 1; + + if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) { + dcs_debug("total_cu: %u, tx_cu: %u, rx_cu: %u, rx_time_cu: %u, unused cu: %u", + reg_total_cu, reg_tx_cu, + reg_rx_cu, rx_time_cu, reg_unused_cu); + dcs_debug("phyerr: %u, total_wasted_cu: %u, phyerror_cu: %u, wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u", + too_many_phy_errors, total_wasted_cu, + reg_ofdm_phyerr_cu, wasted_tx_cu, + reg_tx_cu, reg_rx_cu); + dcs_debug("tx_err: %u", tx_err); + } + + if (reg_unused_cu >= dcs_host_params.coch_intfr_threshold) + /* Quickly reach to decision */ + dcs_im_stats.im_intfr_cnt += 2; + else if (too_many_phy_errors && + (((total_wasted_cu > + (dcs_host_params.coch_intfr_threshold + 10)) && + ((reg_tx_cu + reg_rx_cu) > dcs_host_params.user_max_cu)) || + ((reg_tx_cu > DCS_TX_MAX_CU) && + (tx_err >= dcs_host_params.tx_err_threshold)))) + dcs_im_stats.im_intfr_cnt++; + + if (dcs_im_stats.im_intfr_cnt >= + dcs_host_params.intfr_detection_threshold) { + if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_CRITICAL)) { + dcs_debug("interference threshold exceeded"); + dcs_debug("unused_cu: %u, too_any_phy_errors: %u, total_wasted_cu: %u, reg_tx_cu: %u, reg_rx_cu: %u", + reg_unused_cu, too_many_phy_errors, + total_wasted_cu, reg_tx_cu, reg_rx_cu); + } + + dcs_im_stats.im_intfr_cnt = 0; + dcs_im_stats.im_samp_cnt = 0; + /* + * Once the interference is detected, change the channel, as on + * today this is common routine for wirelesslan and + * non-wirelesslan interference. Name as such kept the same + * because of the DA code, which is using the same function. + */ + start_dcs_cbk_handler = true; + } else if (!dcs_im_stats.im_intfr_cnt || + dcs_im_stats.im_samp_cnt >= + dcs_host_params.intfr_detection_window) { + dcs_im_stats.im_intfr_cnt = 0; + dcs_im_stats.im_samp_cnt = 0; + } + + /* Count the current run too */ + dcs_im_stats.im_samp_cnt++; + + /* Copy the stats for next cycle */ + wlan_dcs_im_copy_stats(prev_stats, curr_stats); + + if (unlikely(dcs_host_params.dcs_debug >= DCS_DEBUG_VERBOSE)) + dcs_debug("intfr_count: %u, sample_count: %u", + dcs_im_stats.im_intfr_cnt, dcs_im_stats.im_samp_cnt); + +end: + return start_dcs_cbk_handler; +} + +void wlan_dcs_disable_timer_fn(void *dcs_timer_args) +{ + struct pdev_dcs_timer_args *dcs_timer_args_ctx; + struct wlan_objmgr_psoc *psoc; + uint32_t pdev_id; + struct dcs_psoc_priv_obj *dcs_psoc_priv; + struct dcs_pdev_priv_obj *dcs_pdev_priv; + + if (!dcs_timer_args) { + dcs_err("dcs timer args is null"); + return; + } + + dcs_timer_args_ctx = (struct pdev_dcs_timer_args *)dcs_timer_args; + psoc = dcs_timer_args_ctx->psoc; + pdev_id = dcs_timer_args_ctx->pdev_id; + + dcs_psoc_priv = + wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_DCS); + if (!dcs_psoc_priv) { + dcs_err("dcs psoc private object is null"); + return; + } + + dcs_pdev_priv = &dcs_psoc_priv->dcs_pdev_priv[pdev_id]; + + qdf_mem_set(&dcs_pdev_priv->dcs_im_stats, + sizeof(dcs_pdev_priv->dcs_im_stats), 0); + dcs_pdev_priv->dcs_freq_ctrl_params.disable_delay_process = false; + + dcs_info("dcs disable timeout, enable dcs detection again"); + wlan_dcs_cmd_send(psoc, pdev_id, true); +} + +/** + * wlan_dcs_frequency_control() - dcs frequency control handling + * @psoc: psoc pointer + * @dcs_pdev_priv: dcs pdev priv pointer + * @event: dcs stats event pointer + * + * Return: none + */ +static void wlan_dcs_frequency_control(struct wlan_objmgr_psoc *psoc, + struct dcs_pdev_priv_obj *dcs_pdev_priv, + struct dcs_stats_event *event) +{ + struct dcs_psoc_priv_obj *dcs_psoc_priv; + struct pdev_dcs_freq_ctrl_params *dcs_freq_ctrl_params; + uint8_t timestamp_pos; + unsigned long current_time; + uint8_t delta_pos; + unsigned long delta_time; + bool disable_dcs_sometime = false; + + if (!psoc || !dcs_pdev_priv || !event) { + dcs_err("psoc or dcs_pdev_priv or event is null"); + return; + } + + dcs_freq_ctrl_params = &dcs_pdev_priv->dcs_freq_ctrl_params; + if (dcs_freq_ctrl_params->disable_delay_process) { + dcs_err("In the process of dcs disable, shouldn't go to here"); + return; + } + + current_time = qdf_get_system_timestamp(); + if (dcs_freq_ctrl_params->dcs_happened_count >= + dcs_freq_ctrl_params->disable_threshold_per_5mins) { + delta_pos = + dcs_freq_ctrl_params->dcs_happened_count - + dcs_freq_ctrl_params->disable_threshold_per_5mins; + delta_pos = delta_pos % MAX_DCS_TIME_RECORD; + + delta_time = current_time - + dcs_freq_ctrl_params->timestamp[delta_pos]; + if (delta_time < DCS_FREQ_CONTROL_TIME) + disable_dcs_sometime = true; + } + + if (!disable_dcs_sometime) { + timestamp_pos = dcs_freq_ctrl_params->dcs_happened_count % + MAX_DCS_TIME_RECORD; + dcs_freq_ctrl_params->timestamp[timestamp_pos] = current_time; + dcs_freq_ctrl_params->dcs_happened_count++; + } + + /* + * Before start dcs callback handler or disable dcs for some time, + * need to send dcs command to disable dcs detection firstly. + */ + wlan_dcs_disable_cmd_send(psoc, event->dcs_param.pdev_id, true); + + if (disable_dcs_sometime) { + dcs_freq_ctrl_params->disable_delay_process = true; + dcs_pdev_priv->dcs_timer_args.psoc = psoc; + dcs_pdev_priv->dcs_timer_args.pdev_id = + event->dcs_param.pdev_id; + qdf_timer_start(&dcs_pdev_priv->dcs_disable_timer, + dcs_pdev_priv->dcs_freq_ctrl_params. + restart_delay * 60 * 1000); + dcs_info("start dcs disable timer"); + } else { + dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj( + psoc, + WLAN_UMAC_COMP_DCS); + if (!dcs_psoc_priv) { + dcs_err("dcs private psoc object is null"); + return; + } + + dcs_info("start dcs callback handler"); + dcs_psoc_priv->dcs_cbk.cbk(psoc, event->dcs_param.pdev_id, + event->dcs_param.interference_type, + dcs_psoc_priv->dcs_cbk.arg); + } +} + +QDF_STATUS +wlan_dcs_process(struct wlan_objmgr_psoc *psoc, struct dcs_stats_event *event) +{ + struct dcs_pdev_priv_obj *dcs_pdev_priv; + bool start_dcs_cbk_handler = false; + + if (!psoc || !event) { + dcs_err("psoc or event is NULL"); + return QDF_STATUS_E_INVAL; + } + + dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, + event->dcs_param.pdev_id); + if (!dcs_pdev_priv) { + dcs_err("dcs pdev private object is null"); + return QDF_STATUS_E_INVAL; + } + + if (unlikely(dcs_pdev_priv->dcs_host_params.dcs_debug + >= DCS_DEBUG_VERBOSE)) + dcs_debug("dcs_enable: %u, interference_type: %u", + dcs_pdev_priv->dcs_host_params.dcs_enable, + event->dcs_param.interference_type); + + if (!dcs_pdev_priv->dcs_host_params.dcs_enable) + return QDF_STATUS_SUCCESS; + + switch (event->dcs_param.interference_type) { + case CAP_DCS_CWIM: + break; + case CAP_DCS_WLANIM: + if (dcs_pdev_priv->dcs_host_params.dcs_enable & CAP_DCS_WLANIM) + start_dcs_cbk_handler = + wlan_dcs_wlan_interference_process( + &event->wlan_stat, + dcs_pdev_priv); + if (start_dcs_cbk_handler) + wlan_dcs_frequency_control(psoc, + dcs_pdev_priv, + event); + break; + default: + dcs_err("unidentified interference type reported"); + break; + } + + return QDF_STATUS_SUCCESS; +} diff --git a/umac/dcs/core/src/wlan_dcs.h b/umac/dcs/core/src/wlan_dcs.h new file mode 100644 index 0000000000..5ac343dbf8 --- /dev/null +++ b/umac/dcs/core/src/wlan_dcs.h @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file has main dcs structures definition. + */ + +#ifndef _WLAN_DCS_H_ +#define _WLAN_DCS_H_ + +#include +#include "wlan_dcs_tgt_api.h" +#include "wlan_dcs_ucfg_api.h" + +#define dcs_debug(args ...) \ + QDF_TRACE_DEBUG(QDF_MODULE_ID_DCS, ## args) +#define dcs_info(args ...) \ + QDF_TRACE_INFO(QDF_MODULE_ID_DCS, ## args) +#define dcs_err(args ...) \ + QDF_TRACE_ERROR(QDF_MODULE_ID_DCS, ## args) + +#define DCS_TX_MAX_CU 30 +#define MAX_DCS_TIME_RECORD 10 +#define DCS_FREQ_CONTROL_TIME (5 * 60 * 1000) + +/** + * enum wlan_dcs_debug_level - dcs debug trace level + * @DCS_DEBUG_DISABLE: disable debug trace + * @DCS_DEBUG_CRITICAL: critical debug trace level + * @DCS_DEBUG_VERBOSE: verbose debug trace level + */ +enum wlan_dcs_debug_level { + DCS_DEBUG_DISABLE = 0, + DCS_DEBUG_CRITICAL = 1, + DCS_DEBUG_VERBOSE = 2 +}; + +/** + * struct pdev_dcs_im_stats - define dcs interference mitigation + * stats in pdev object + * @prev_dcs_im_stats: previous statistics at last time + * @im_intfr_cnt: number of times the interference is + * detected within detection window + * @im_sample_cnt: sample counter + */ +struct pdev_dcs_im_stats { + struct wlan_host_dcs_im_tgt_stats prev_dcs_im_stats; + uint8_t im_intfr_cnt; + uint8_t im_samp_cnt; +}; + +/** + * struct pdev_dcs_params - define dcs configuration parameter in pdev object + * @dcs_enable_cfg: dcs enable from ini config + * @dcs_enable: dcs enable from ucfg config + * @dcs_debug: dcs debug trace level + * @phy_err_penalty: phy error penalty + * @phy_err_threshold: phy error threshold + * @radar_err_threshold: radar error threshold + * @coch_intfr_threshold: co-channel interference threshold + * @user_max_cu: tx channel utilization due to AP's tx and rx + * @intfr_detection_threshold: interference detection threshold + * @intfr_detection_window: interference sampling window + * @tx_err_threshold: transmission failure rate threshold + */ +struct pdev_dcs_params { + uint8_t dcs_enable_cfg; + uint8_t dcs_enable; + enum wlan_dcs_debug_level dcs_debug; + uint32_t phy_err_penalty; + uint32_t phy_err_threshold; + uint32_t radar_err_threshold; + uint32_t coch_intfr_threshold; + uint32_t user_max_cu; + uint32_t intfr_detection_threshold; + uint32_t intfr_detection_window; + uint32_t tx_err_threshold; +}; + +/** + * struct pdev_dcs_freq_ctrl_params - define dcs frequency control parameter + * in pdebv object + * @disable_threshold_per_5mins: in five minutes, if dcs happen more than + * threshold, then disable dcs for some time + * @restart_delay: when dcs happen more than threshold in five minutes, + * then start to disable dcs for restart_delay minutes + * @timestamp: record dcs happened timestamp + * @dcs_happened_count: dcs happened count + * @disable_delay_process: in dcs disable delay process or not + */ +struct pdev_dcs_freq_ctrl_params { + uint8_t disable_threshold_per_5mins; + uint32_t restart_delay; + unsigned long timestamp[MAX_DCS_TIME_RECORD]; + unsigned long dcs_happened_count; + bool disable_delay_process; +}; + +/** + * struct pdev_dcs_timer_args - define pdev dcs timer args + * @psoc: psoc pointer + * @pdev_id: pdev id + */ +struct pdev_dcs_timer_args { + struct wlan_objmgr_psoc *psoc; + uint32_t pdev_id; +}; + +/** + * struct psoc_dcs_cbk - define dcs callback in psoc oject + * @cbk: callback + * @arg: arguments + */ +struct psoc_dcs_cbk { + dcs_callback cbk; + void *arg; +}; + +/** + * struct dcs_pdev_priv_obj - define dcs pdev priv + * @dcs_host_params: dcs host configuration parameter + * @dcs_im_stats: dcs im statistics + * @dcs_freq_ctrl_params: dcs frequency control parameter + * @dcs_disable_timer: dcs disable timer + * @dcs_timer_args: dcs disable timer args + */ +struct dcs_pdev_priv_obj { + struct pdev_dcs_params dcs_host_params; + struct pdev_dcs_im_stats dcs_im_stats; + struct pdev_dcs_freq_ctrl_params dcs_freq_ctrl_params; + qdf_timer_t dcs_disable_timer; + struct pdev_dcs_timer_args dcs_timer_args; +}; + +/** + * struct dcs_psoc_priv_obj - define dcs psoc priv + * @dcs_pdev_priv: dcs pdev priv + * @dcs_cbk: dcs callback + */ +struct dcs_psoc_priv_obj { + struct dcs_pdev_priv_obj dcs_pdev_priv[WLAN_UMAC_MAX_PDEVS]; + struct psoc_dcs_cbk dcs_cbk; +}; + +/** + * wlan_dcs_get_pdev_private_obj() - get dcs pdev private object + * @psoc: psoc pointer + * @pdev_id: pdev_id + * + * API to retrieve the pdev private object from the psoc context + * + * Return: pdev private object pointer on success, NULL on error + */ +struct dcs_pdev_priv_obj * +wlan_dcs_get_pdev_private_obj(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id); + +/** + * wlan_dcs_attach() - Attach dcs handler + * @psoc: psoc pointer + * + * This function gets called to register dcs FW events handler + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_dcs_attach(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_dcs_detach() - Detach dcs handler + * @psoc: psoc pointer + * + * This function gets called to unregister dcs FW events handler + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_dcs_detach(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_dcs_cmd_send() - Send dcs command to target_if layer + * @psoc: psoc pointer + * @pdev_id: pdev_id + * @is_target_pdev_id: pdev_id is target id or not + * + * The function gets called to send dcs command to FW + * + * return: QDF_STATUS_SUCCESS for success or error code + */ +QDF_STATUS wlan_dcs_cmd_send(struct wlan_objmgr_psoc *psoc, + uint32_t pdev_id, + bool is_target_pdev_id); + +/** + * wlan_dcs_process() - dcs process main entry + * @psoc: psoc pointer + * @event: dcs stats event pointer + * + * This function is the main entry to do dcs related operation + * such as algorithm handling and dcs frequency control. + * + * Return: QDF_STATUS + */ +QDF_STATUS wlan_dcs_process(struct wlan_objmgr_psoc *psoc, + struct dcs_stats_event *event); + +/** + * wlan_dcs_disable_timer_fn() - dcs disable timer callback + * @dcs_timer_args: dcs timer argument pointer + * + * This function gets called when dcs disable timer timeout + * + * Return: None + */ +void wlan_dcs_disable_timer_fn(void *dcs_timer_args); + +#endif /* _WLAN_DCS_H_ */ diff --git a/umac/dcs/dispatcher/inc/wlan_dcs_cfg.h b/umac/dcs/dispatcher/inc/wlan_dcs_cfg.h new file mode 100644 index 0000000000..51a36dbf45 --- /dev/null +++ b/umac/dcs/dispatcher/inc/wlan_dcs_cfg.h @@ -0,0 +1,309 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains centralized definitions of DCS component + */ +#ifndef __CONFIG_DCS_H +#define __CONFIG_DCS_H + +#include "cfg_define.h" + +/* + * + * gEnableDcs - Enable/Disable DCS + * @Min: 0 + * @Max: 3 + * @Default: 0 + * + * This ini is used to enable/disable DCS. Configurations are as follows: + * 0 - Disable DCS. + * 1 - Enable DCS for CW interference mitigation(CW_IM). + * 2 - Enable DCS for WLAN interference mitigation(WLAN_IM). + * 3 - Enable both DCS for CW_IM and DCS for WLAN_IM. + * + * Related: None + * + * Supported Feature: DCS + * + * Usage: External + * + * + */ +#define CFG_DCS_ENABLE CFG_INI_UINT(\ + "gEnableDcs",\ + 0, 3, 0,\ + CFG_VALUE_OR_DEFAULT, "Enable DCS") + +/* + * + * dcs_debug - Configure dcs debug trace level for debug purpose + * @Min: 0 + * @Max: 2 + * @Default: 0 + * + * This ini is used to configure dcs debug trace level for debug purpose + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DCS_DEBUG CFG_INI_UINT(\ + "dcs_debug",\ + 0, 2, 0,\ + CFG_VALUE_OR_DEFAULT,\ + "dcs debug trace level") + +/* + * + * dcs_coch_intfr_threshold - Configure co-channel interference threshold + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 30 + * + * This ini is used to configure co-channel interference threshold + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DCS_COCH_INTFR_THRESHOLD CFG_INI_UINT(\ + "dcs_coch_intfr_threshold",\ + 0, 0xFFFFFFFF, 30,\ + CFG_VALUE_OR_DEFAULT,\ + "dcs co-channel interference threshold level") + +/* + * + * dcs_tx_err_threshold - Configure transmission failure rate threshold + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 30 + * + * This ini is used to configure transmission failure rate threshold + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DCS_TX_ERR_THRESHOLD CFG_INI_UINT(\ + "dcs_tx_err_threshold",\ + 0, 0xFFFFFFFF, 30,\ + CFG_VALUE_OR_DEFAULT,\ + "dcs transmission failure rate threshold") + +/* + * + * dcs_phy_err_penalty - Configure channel time wasted due to each Phy + * error(phy error penalty) + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 500 + * + * This ini is used to configure phy error penalty + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DCS_PHY_ERR_PENALTY CFG_INI_UINT(\ + "dcs_phy_err_penalty",\ + 0, 0xFFFFFFFF, 500,\ + CFG_VALUE_OR_DEFAULT,\ + "dcs phy error penalty") + +/* + * + * dcs_phy_err_threshold - Configure phy err threshold + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 300 + * + * This ini is used to configure phy error threshold + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DCS_PHY_ERR_THRESHOLD CFG_INI_UINT(\ + "dcs_phy_err_threshold",\ + 0, 0xFFFFFFFF, 300,\ + CFG_VALUE_OR_DEFAULT,\ + "dcs phy error threshold") + +/* + * + * dcs_user_max_cu - Configure tx channel utilization due to AP's tx and rx + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 50 + * + * This ini is used to configure tx channel utilization due to AP's tx and rx + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DCS_USER_MAX_CU CFG_INI_UINT(\ + "user_max_cu",\ + 0, 0xFFFFFFFF, 50,\ + CFG_VALUE_OR_DEFAULT,\ + "dcs tx channel utilization") + +/* + * + * dcs_radar_err_threshold - Configure radar error threshold + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 1000 + * + * This ini is used to configure radar error threshold + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DCS_RADAR_ERR_THRESHOLD CFG_INI_UINT(\ + "dcs_radar_err_threshold",\ + 0, 0xFFFFFFFF, 1000,\ + CFG_VALUE_OR_DEFAULT,\ + "dcs radar error threshold") + +/* + * + * dcs_intfr_detection_threshold - Configure interference detection threshold + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 6 + * + * This ini is used to configure interference detection threshold + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DCS_INTFR_DETECTION_THRESHOLD CFG_INI_UINT(\ + "dcs_intfr_detection_threshold",\ + 0, 0xFFFFFFFF, 6,\ + CFG_VALUE_OR_DEFAULT,\ + "dcs interference detection threshold") + +/* + * + * dcs_intfr_detection_window - Configure interference sampling window + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 10 + * + * This ini is used to configure interference sampling window + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DCS_INTFR_DETECTION_WINDOW CFG_INI_UINT(\ + "dcs_intfr_detection_window",\ + 0, 0xFFFFFFFF, 10,\ + CFG_VALUE_OR_DEFAULT,\ + "dcs interference sampling window") + +/* + * + * dcs_disable_threshold_per_5mins - In five minutes, if dcs happen + * more than threshold, then disable dcs for some time + * @Min: 0 + * @Max: 10 + * @Default: 3 + * + * This ini is used to dcs happen times threshold in five minutes + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DCS_DISABLE_THRESHOLD_PER_5MINS CFG_INI_UINT(\ + "dcs_disable_thresh_per_5mins",\ + 0, 10, 3,\ + CFG_VALUE_OR_DEFAULT,\ + "dcs happen times threshold in five minutes") + +/* + * + * dcs_restart_delay - When dcs happen more than threshold in five minutes, + * then start to disable dcs for some minutes, then enable dcs again. + * @Min: 0 + * @Max: 0xFFFFFFFF + * @Default: 30 + * + * This ini is used to configure dcs disable time length in minute unit + * + * + * Related: None + * + * Usage: External + * + * + */ +#define CFG_DCS_RESTART_DELAY CFG_INI_UINT(\ + "dcs_restart_delay",\ + 0, 0xFFFFFFFF, 30,\ + CFG_VALUE_OR_DEFAULT, "dcs restart delay") + +#define CFG_DCS_ALL \ + CFG(CFG_DCS_ENABLE) \ + CFG(CFG_DCS_DEBUG) \ + CFG(CFG_DCS_COCH_INTFR_THRESHOLD) \ + CFG(CFG_DCS_TX_ERR_THRESHOLD) \ + CFG(CFG_DCS_PHY_ERR_PENALTY) \ + CFG(CFG_DCS_PHY_ERR_THRESHOLD) \ + CFG(CFG_DCS_USER_MAX_CU) \ + CFG(CFG_DCS_RADAR_ERR_THRESHOLD) \ + CFG(CFG_DCS_INTFR_DETECTION_THRESHOLD) \ + CFG(CFG_DCS_INTFR_DETECTION_WINDOW) \ + CFG(CFG_DCS_DISABLE_THRESHOLD_PER_5MINS) \ + CFG(CFG_DCS_RESTART_DELAY) + +#endif /* __CONFIG_DCS_H */ diff --git a/umac/dcs/dispatcher/inc/wlan_dcs_init_deinit_api.h b/umac/dcs/dispatcher/inc/wlan_dcs_init_deinit_api.h new file mode 100644 index 0000000000..be0454a875 --- /dev/null +++ b/umac/dcs/dispatcher/inc/wlan_dcs_init_deinit_api.h @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_dcs_init_deinit_api.h + * + * This header file provide declaration to public APIs exposed for other UMAC + * components to init/deinit, (de)register to required WMI events on + * soc enable/disable + */ + +#ifndef __WLAN_DCS_INIT_DEINIT_API_H__ +#define __WLAN_DCS_INIT_DEINIT_API_H__ + +#ifdef DCS_INTERFERENCE_DETECTION + +#include +#include +#include + +/** + * wlan_dcs_init(): API to init dcs component + * + * This API is invoked from dispatcher init during all component init. + * This API will register all required handlers for pdev object + * create/delete notification. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_dcs_init(void); + +/** + * wlan_dcs_deinit(): API to deinit dcs component + * + * This API is invoked from dispatcher deinit during all component deinit. + * This API will unregister all required handlers for pdev object + * create/delete notification. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_dcs_deinit(void); + +/** + * wlan_dcs_enable(): API to enable dcs component + * @psoc: pointer to psoc + * + * This API is invoked from dispatcher psoc enable. + * This API will register dcs WMI event handlers. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_dcs_enable(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_dcs_disable(): API to disable dcs component + * @psoc: pointer to psoc + * + * This API is invoked from dispatcher psoc disable. + * This API will unregister dcs WMI event handlers. + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_dcs_disable(struct wlan_objmgr_psoc *psoc); + +/** + * wlan_dcs_psoc_open() - Dcs psoc open handler + * @psoc: pointer to psoc object + * + * API to execute operations on psoc open + * + * Return: QDF_STATUS_SUCCESS upon successful registration, + * QDF_STATUS_E_FAILURE upon failure + */ +QDF_STATUS wlan_dcs_psoc_open(struct wlan_objmgr_psoc *psoc); + +#endif /* DCS_INTERFERENCE_DETECTION */ +#endif /* __WLAN_DCS_INIT_DEINIT_API_H__ */ + diff --git a/umac/dcs/dispatcher/inc/wlan_dcs_public_structs.h b/umac/dcs/dispatcher/inc/wlan_dcs_public_structs.h new file mode 100644 index 0000000000..c4bbd7e374 --- /dev/null +++ b/umac/dcs/dispatcher/inc/wlan_dcs_public_structs.h @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: contains dcs structure definations + */ + +#ifndef _WLAN_DCS_PUBLIC_STRUCTS_H_ +#define _WLAN_DCS_PUBLIC_STRUCTS_H_ + +/** + * struct wlan_host_dcs_interference_param - dcs interference parameters + * @interference_type: type of DCS interference + * @uint32_t pdev_id: pdev id + */ +struct wlan_host_dcs_interference_param { + uint32_t interference_type; + uint32_t pdev_id; +}; + +/** + * struct wlan_host_dcs_mib_stats - WLAN IM stats from target to host + * @listen_time: + * @reg_tx_frame_cnt: + * @reg_rx_frame_cnt: + * @reg_rxclr_cnt: + * @reg_cycle_cnt: delta cycle count + * @reg_rxclr_ext_cnt: + * @reg_ofdm_phyerr_cnt: + * @reg_cck_phyerr_cnt: CCK err count since last reset, read from register + */ +struct wlan_host_dcs_mib_stats { + int32_t listen_time; + uint32_t reg_tx_frame_cnt; + uint32_t reg_rx_frame_cnt; + uint32_t reg_rxclr_cnt; + uint32_t reg_cycle_cnt; + uint32_t reg_rxclr_ext_cnt; + uint32_t reg_ofdm_phyerr_cnt; + uint32_t reg_cck_phyerr_cnt; +}; + +/** + * struct wlan_host_dcs_im_tgt_stats - DCS IM target stats + * @reg_tsf32: current running TSF from the TSF-1 + * @last_ack_rssi: known last frame rssi, in case of multiple stations, if + * and at different ranges, this would not gaurantee that + * this is the least rssi. + * @tx_waste_time: sum of all the failed durations in the last + * one second interval. + * @rx_time: count how many times the hal_rxerr_phy is marked, in this + * time period + * @phyerr_cnt: + * @mib_stats: collected mib stats as explained in mib structure + * @chan_nf: Channel noise floor (units are in dBm) + * @my_bss_rx_cycle_count: BSS rx cycle count + * @reg_rxclr_ext40_cnt: extension channel 40Mhz rxclear count + * @reg_rxclr_ext80_cnt: extension channel 80Mhz rxclear count + */ +struct wlan_host_dcs_im_tgt_stats { + uint32_t reg_tsf32; + uint32_t last_ack_rssi; + uint32_t tx_waste_time; + uint32_t rx_time; + uint32_t phyerr_cnt; + struct wlan_host_dcs_mib_stats mib_stats; + uint32_t chan_nf; + uint32_t my_bss_rx_cycle_count; + uint32_t reg_rxclr_ext40_cnt; + uint32_t reg_rxclr_ext80_cnt; +}; + +#endif diff --git a/umac/dcs/dispatcher/inc/wlan_dcs_tgt_api.h b/umac/dcs/dispatcher/inc/wlan_dcs_tgt_api.h new file mode 100644 index 0000000000..f8cf5976f9 --- /dev/null +++ b/umac/dcs/dispatcher/inc/wlan_dcs_tgt_api.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: wlan_dcs_tgt_api.h + * + * This header file provide with API declarations to interface with Southbound + */ +#ifndef __WLAN_DCS_TGT_API_H__ +#define __WLAN_DCS_TGT_API_H__ + +#include +#include + +/** + * struct dcs_stats_event - define dcs stats event + * @wlan_stat: wlan interference target statistics + * @dcs_param: dcs event param + */ +struct dcs_stats_event { + struct wlan_host_dcs_im_tgt_stats wlan_stat; + struct wlan_host_dcs_interference_param dcs_param; +}; + +/** + * tgt_dcs_process_event(): dcs FW event process + * @psoc: pointer to psoc object + * @event: pointer to dcs stats event + * + * This function gets called to process dcs FW event + * + * Return: QDF_STATUS + */ +QDF_STATUS tgt_dcs_process_event(struct wlan_objmgr_psoc *psoc, + struct dcs_stats_event *event); + +#endif /* __WLAN_DCS_TGT_API_H__ */ diff --git a/umac/dcs/dispatcher/inc/wlan_dcs_ucfg_api.h b/umac/dcs/dispatcher/inc/wlan_dcs_ucfg_api.h new file mode 100644 index 0000000000..8fdbbb6434 --- /dev/null +++ b/umac/dcs/dispatcher/inc/wlan_dcs_ucfg_api.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file has the dcs dispatcher API which is exposed to outside of dcs + * component. + */ +#ifndef _WLAN_DCS_UCFG_API_H_ +#define _WLAN_DCS_UCFG_API_H_ + +#include +#include + +/** + * @brief List of DCS capabilities that can be set or unset + * dynamically + * @see UMAC auto channel selection document for details on each feature + * + */ +#define CAP_DCS_CWIM 0x1 +#define CAP_DCS_WLANIM 0x2 +#define CAP_DCS_MASK (CAP_DCS_CWIM | CAP_DCS_WLANIM) + +/** + * typedef dcs_callback() - DCS callback + * @psoc: Pointer to psoc + * @pdev_id: pdev id + * @interference_type: interference type + * @arg: list of arguments + */ +typedef void (*dcs_callback)( + struct wlan_objmgr_psoc *psoc, + uint8_t pdev_id, + uint8_t interference_type, + void *arg); + +/** + * ucfg_dcs_register_cb() - API to register dcs callback + * @psoc: pointer to psoc object + * @cbk: dcs callback to be registered + * @arg: argument + * + * This function gets called to register dcs callback function + * + * Return: None + */ +void ucfg_dcs_register_cb( + struct wlan_objmgr_psoc *psoc, + dcs_callback cbk, + void *arg); + +/** + * ucfg_wlan_dcs_cmd(): API to send dcs command + * @psoc: pointer to psoc object + * @pdev_id: pdev_id + * @is_target_pdev_id: pdev_id is target id or not + * + * This function gets called to send dcs command + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS +ucfg_wlan_dcs_cmd(struct wlan_objmgr_psoc *psoc, + uint32_t pdev_id, + bool is_target_pdev_id); + +/** + * ucfg_config_dcs_enable() - API to config dcs enable + * @psoc: pointer to psoc object + * @pdev_id: pdev id + * @interference_type: CAP_DCS_CWIM, CAP_DCS_WLANIM, CAP_DCS_MASK + * + * This function gets called to config dcs enable + * + * Return: None + */ +void ucfg_config_dcs_enable(struct wlan_objmgr_psoc *psoc, + uint32_t pdev_id, + uint8_t interference_type); + +/** + * ucfg_config_dcs_disable() - API to config dcs disable + * @psoc: pointer to psoc object + * @pdev_id: pdev id + * @interference_type: CAP_DCS_CWIM, CAP_DCS_WLANIM, CAP_DCS_MASK + * + * This function gets called to config dcs disable + * + * Return: None + */ +void ucfg_config_dcs_disable(struct wlan_objmgr_psoc *psoc, + uint32_t pdev_id, + uint8_t interference_type); + +/** + * ucfg_get_dcs_enable() - API to get dcs enable + * @psoc: pointer to psoc object + * @pdev_id: pdev id + * + * This function gets called to get current host + * config dcs enable/disable status + * + * Return: WLANIM/CWIM enable status + */ +uint8_t ucfg_get_dcs_enable(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id); + +#endif /* _WLAN_DCS_UCFG_API_H_ */ diff --git a/umac/dcs/dispatcher/src/wlan_dcs_init_deinit_api.c b/umac/dcs/dispatcher/src/wlan_dcs_init_deinit_api.c new file mode 100644 index 0000000000..6711db0f9f --- /dev/null +++ b/umac/dcs/dispatcher/src/wlan_dcs_init_deinit_api.c @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file init/deint functions for dcs module. + */ + +#include "wlan_dcs_init_deinit_api.h" +#include "../../core/src/wlan_dcs.h" +#include "wlan_dcs_cfg.h" +#include "cfg_ucfg_api.h" + +/** + * wlan_dcs_psoc_obj_create_notification() - dcs psoc cretae handler + * @psoc: psoc object + * @arg_list: Argument list + * + * return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS +wlan_dcs_psoc_obj_create_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list) +{ + QDF_STATUS status; + struct dcs_psoc_priv_obj *dcs_psoc_obj; + + dcs_psoc_obj = qdf_mem_malloc(sizeof(*dcs_psoc_obj)); + + if (!dcs_psoc_obj) + return QDF_STATUS_E_NOMEM; + + status = wlan_objmgr_psoc_component_obj_attach(psoc, + WLAN_UMAC_COMP_DCS, + dcs_psoc_obj, + QDF_STATUS_SUCCESS); + + if (QDF_IS_STATUS_ERROR(status)) { + dcs_err("dcs pdev obj attach failed"); + qdf_mem_free(dcs_psoc_obj); + return status; + } + + dcs_info("dcs psoc object attached"); + + return status; +} + +/** + * wlan_dcs_psoc_obj_destroy_notification() - dcs psoc destroy handler + * @psoc: psoc object + * @arg_list: Argument list + * + * return: QDF_STATUS_SUCCESS for success or error code + */ +static QDF_STATUS +wlan_dcs_psoc_obj_destroy_notification(struct wlan_objmgr_psoc *psoc, + void *arg_list) +{ + QDF_STATUS status; + uint8_t loop; + struct dcs_psoc_priv_obj *dcs_psoc_obj = + wlan_objmgr_psoc_get_comp_private_obj(psoc, WLAN_UMAC_COMP_DCS); + + if (!dcs_psoc_obj) { + dcs_err("invalid wifi dcs obj"); + return QDF_STATUS_E_FAULT; + } + + status = wlan_objmgr_psoc_component_obj_detach(psoc, + WLAN_UMAC_COMP_DCS, + dcs_psoc_obj); + for (loop = 0; loop < WLAN_UMAC_MAX_PDEVS; loop++) + qdf_timer_free(&dcs_psoc_obj->dcs_pdev_priv[loop]. + dcs_disable_timer); + qdf_mem_free(dcs_psoc_obj); + + return status; +} + +QDF_STATUS wlan_dcs_init(void) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = wlan_objmgr_register_psoc_create_handler( + WLAN_UMAC_COMP_DCS, + wlan_dcs_psoc_obj_create_notification, + NULL); + + if (QDF_IS_STATUS_ERROR(status)) + goto err_psoc_create; + + status = wlan_objmgr_register_psoc_destroy_handler( + WLAN_UMAC_COMP_DCS, + wlan_dcs_psoc_obj_destroy_notification, + NULL); + + if (QDF_IS_STATUS_ERROR(status)) + goto err_psoc_delete; + + return QDF_STATUS_SUCCESS; + +err_psoc_delete: + wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_DCS, + wlan_dcs_psoc_obj_create_notification, + NULL); +err_psoc_create: + return status; +} + +QDF_STATUS wlan_dcs_deinit(void) +{ + QDF_STATUS status = QDF_STATUS_SUCCESS; + + status = wlan_objmgr_unregister_psoc_create_handler( + WLAN_UMAC_COMP_DCS, + wlan_dcs_psoc_obj_create_notification, + NULL); + + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + + status = wlan_objmgr_unregister_psoc_destroy_handler( + WLAN_UMAC_COMP_DCS, + wlan_dcs_psoc_obj_destroy_notification, + NULL); + + if (QDF_IS_STATUS_ERROR(status)) + return QDF_STATUS_E_FAILURE; + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS wlan_dcs_enable(struct wlan_objmgr_psoc *psoc) +{ + return wlan_dcs_attach(psoc); +} + +QDF_STATUS wlan_dcs_disable(struct wlan_objmgr_psoc *psoc) +{ + return wlan_dcs_detach(psoc); +} + +QDF_STATUS wlan_dcs_psoc_open(struct wlan_objmgr_psoc *psoc) +{ + struct dcs_psoc_priv_obj *dcs_psoc_obj; + struct dcs_pdev_priv_obj *dcs_pdev_priv; + uint8_t loop; + + if (!psoc) { + dcs_err("psoc is NULL"); + return QDF_STATUS_E_INVAL; + } + + dcs_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj( + psoc, WLAN_UMAC_COMP_DCS); + if (!dcs_psoc_obj) { + dcs_err("dcs psoc private object is NULL"); + return QDF_STATUS_E_FAILURE; + } + + for (loop = 0; loop < WLAN_UMAC_MAX_PDEVS; loop++) { + dcs_pdev_priv = &dcs_psoc_obj->dcs_pdev_priv[loop]; + dcs_pdev_priv->dcs_host_params.dcs_enable_cfg = + cfg_get(psoc, CFG_DCS_ENABLE); + dcs_pdev_priv->dcs_host_params.dcs_debug = + cfg_get(psoc, CFG_DCS_DEBUG); + dcs_pdev_priv->dcs_host_params.phy_err_penalty = + cfg_get(psoc, CFG_DCS_PHY_ERR_PENALTY); + dcs_pdev_priv->dcs_host_params.phy_err_threshold = + cfg_get(psoc, CFG_DCS_PHY_ERR_THRESHOLD); + dcs_pdev_priv->dcs_host_params.radar_err_threshold = + cfg_get(psoc, CFG_DCS_RADAR_ERR_THRESHOLD); + dcs_pdev_priv->dcs_host_params.coch_intfr_threshold = + cfg_get(psoc, CFG_DCS_COCH_INTFR_THRESHOLD); + dcs_pdev_priv->dcs_host_params.user_max_cu = + cfg_get(psoc, CFG_DCS_USER_MAX_CU); + dcs_pdev_priv->dcs_host_params.intfr_detection_threshold = + cfg_get(psoc, CFG_DCS_INTFR_DETECTION_THRESHOLD); + dcs_pdev_priv->dcs_host_params.intfr_detection_window = + cfg_get(psoc, CFG_DCS_INTFR_DETECTION_WINDOW); + dcs_pdev_priv->dcs_host_params.tx_err_threshold = + cfg_get(psoc, CFG_DCS_TX_ERR_THRESHOLD); + dcs_pdev_priv->dcs_freq_ctrl_params. + disable_threshold_per_5mins = + cfg_get(psoc, CFG_DCS_DISABLE_THRESHOLD_PER_5MINS); + dcs_pdev_priv->dcs_freq_ctrl_params.restart_delay = + cfg_get(psoc, CFG_DCS_RESTART_DELAY); + + qdf_timer_init(NULL, &dcs_pdev_priv->dcs_disable_timer, + wlan_dcs_disable_timer_fn, + &dcs_pdev_priv->dcs_timer_args, + QDF_TIMER_TYPE_WAKE_APPS); + } + + return QDF_STATUS_SUCCESS; +} diff --git a/umac/dcs/dispatcher/src/wlan_dcs_tgt_api.c b/umac/dcs/dispatcher/src/wlan_dcs_tgt_api.c new file mode 100644 index 0000000000..2b4bd1ec86 --- /dev/null +++ b/umac/dcs/dispatcher/src/wlan_dcs_tgt_api.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC:wlan_dcs_tgt_api.c + * + * This file provide API definitions to update dcs from southbound interface + */ + +#include "wlan_dcs_tgt_api.h" +#include "../../core/src/wlan_dcs.h" + +QDF_STATUS tgt_dcs_process_event(struct wlan_objmgr_psoc *psoc, + struct dcs_stats_event *event) +{ + return wlan_dcs_process(psoc, event); +} diff --git a/umac/dcs/dispatcher/src/wlan_dcs_ucfg_api.c b/umac/dcs/dispatcher/src/wlan_dcs_ucfg_api.c new file mode 100644 index 0000000000..0c44f6fa9b --- /dev/null +++ b/umac/dcs/dispatcher/src/wlan_dcs_ucfg_api.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file has the dcs dispatcher API implementation which is exposed + * to outside of dcs component. + */ + +#include "wlan_dcs_ucfg_api.h" +#include "../../core/src/wlan_dcs.h" + +void ucfg_dcs_register_cb( + struct wlan_objmgr_psoc *psoc, + dcs_callback cbk, + void *arg) +{ + struct dcs_psoc_priv_obj *dcs_psoc_priv; + + dcs_psoc_priv = wlan_objmgr_psoc_get_comp_private_obj( + psoc, + WLAN_UMAC_COMP_DCS); + if (!dcs_psoc_priv) { + dcs_err("dcs psoc private object is null"); + return; + } + + dcs_psoc_priv->dcs_cbk.cbk = cbk; + dcs_psoc_priv->dcs_cbk.arg = arg; +} + +QDF_STATUS +ucfg_wlan_dcs_cmd(struct wlan_objmgr_psoc *psoc, + uint32_t pdev_id, + bool is_target_pdev_id) +{ + return wlan_dcs_cmd_send(psoc, pdev_id, is_target_pdev_id); +} + +void ucfg_config_dcs_enable(struct wlan_objmgr_psoc *psoc, + uint32_t pdev_id, + uint8_t interference_type) +{ + struct dcs_pdev_priv_obj *dcs_pdev_priv; + + dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); + if (!dcs_pdev_priv) { + dcs_err("dcs pdev private object is null"); + return; + } + + dcs_pdev_priv->dcs_host_params.dcs_enable |= interference_type; +} + +void ucfg_config_dcs_disable(struct wlan_objmgr_psoc *psoc, + uint32_t pdev_id, + uint8_t interference_type) +{ + struct dcs_pdev_priv_obj *dcs_pdev_priv; + + dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); + if (!dcs_pdev_priv) { + dcs_err("dcs pdev private object is null"); + return; + } + + dcs_pdev_priv->dcs_host_params.dcs_enable &= (~interference_type); +} + +uint8_t ucfg_get_dcs_enable(struct wlan_objmgr_psoc *psoc, uint32_t pdev_id) +{ + struct dcs_pdev_priv_obj *dcs_pdev_priv; + + dcs_pdev_priv = wlan_dcs_get_pdev_private_obj(psoc, pdev_id); + if (!dcs_pdev_priv) { + dcs_err("dcs pdev private object is null"); + return 0; + } + + return dcs_pdev_priv->dcs_host_params.dcs_enable; +} diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h index 24cecc950b..af44617b28 100644 --- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h +++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h @@ -82,6 +82,10 @@ struct dbr_module_config; #include #include +#ifdef DCS_INTERFERENCE_DETECTION +#include +#endif + #ifdef QCA_SUPPORT_CP_STATS /** * struct wlan_lmac_if_cp_stats_tx_ops - defines southbound tx callbacks for @@ -116,6 +120,33 @@ struct wlan_lmac_if_cp_stats_rx_ops { }; #endif +#ifdef DCS_INTERFERENCE_DETECTION +/** + * struct wlan_target_if_dcs_tx_ops - south bound tx function pointers for dcs + * @dcs_attach: function to register event handlers with FW + * @dcs_detach: function to de-register event handlers with FW + * @dcs_cmd_send: function to send dcs commands to FW + */ +struct wlan_target_if_dcs_tx_ops { + QDF_STATUS (*dcs_attach)(struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*dcs_detach)(struct wlan_objmgr_psoc *psoc); + QDF_STATUS (*dcs_cmd_send)(struct wlan_objmgr_psoc *psoc, + uint32_t pdev_id, + bool is_target_pdev_id, + uint32_t dcs_enable); +}; + +/** + * struct wlan_target_if_dcs_rx_ops - defines southbound rx callbacks for + * dcs component + * @process_dcs_event: function pointer to rx FW events + */ +struct wlan_target_if_dcs_rx_ops { + QDF_STATUS (*process_dcs_event)(struct wlan_objmgr_psoc *psoc, + struct dcs_stats_event *event); +}; +#endif + /** * struct wlan_lmac_if_mgmt_txrx_tx_ops - structure of tx function * pointers for mgmt txrx component @@ -963,6 +994,9 @@ struct wlan_lmac_if_tx_ops { #ifdef QCA_SUPPORT_CP_STATS struct wlan_lmac_if_cp_stats_tx_ops cp_stats_tx_ops; #endif +#ifdef DCS_INTERFERENCE_DETECTION + struct wlan_target_if_dcs_tx_ops dcs_tx_ops; +#endif #ifdef WLAN_SA_API_ENABLE struct wlan_lmac_if_sa_api_tx_ops sa_api_tx_ops; #endif @@ -1652,6 +1686,9 @@ struct wlan_lmac_if_rx_ops { #ifdef QCA_SUPPORT_CP_STATS struct wlan_lmac_if_cp_stats_rx_ops cp_stats_rx_ops; #endif +#ifdef DCS_INTERFERENCE_DETECTION + struct wlan_target_if_dcs_rx_ops dcs_rx_ops; +#endif #ifdef WLAN_SA_API_ENABLE struct wlan_lmac_if_sa_api_rx_ops sa_api_rx_ops; #endif diff --git a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c index cd8fdf12a2..d21d4e840f 100644 --- a/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c +++ b/umac/global_umac_dispatcher/lmac_if/src/wlan_lmac_if.c @@ -108,6 +108,27 @@ wlan_lmac_if_cp_stats_rx_ops_register(struct wlan_lmac_if_rx_ops *rx_ops) } #endif /* QCA_SUPPORT_CP_STATS */ +#ifdef DCS_INTERFERENCE_DETECTION +/** + * wlan_target_if_dcs_rx_ops_register() - API to register dcs Rx Ops + * @rx_ops: pointer to lmac rx ops + * + * This API will be used to register function pointers for FW events + * + * Return: void + */ +static void +wlan_target_if_dcs_rx_ops_register(struct wlan_lmac_if_rx_ops *rx_ops) +{ + rx_ops->dcs_rx_ops.process_dcs_event = tgt_dcs_process_event; +} +#else +static void +wlan_target_if_dcs_rx_ops_register(struct wlan_lmac_if_rx_ops *rx_ops) +{ +} +#endif /* DCS_INTERFERENCE_DETECTION */ + #ifdef WLAN_ATF_ENABLE /** * wlan_lmac_if_atf_rx_ops_register() - Function to register ATF RX ops. @@ -653,6 +674,8 @@ wlan_lmac_if_umac_rx_ops_register(struct wlan_lmac_if_rx_ops *rx_ops) wlan_lmac_if_cp_stats_rx_ops_register(rx_ops); + wlan_target_if_dcs_rx_ops_register(rx_ops); + wlan_lmac_if_sa_api_rx_ops_register(rx_ops); wlan_lmac_if_cfr_rx_ops_register(rx_ops); diff --git a/wmi/inc/wmi_unified_dcs_api.h b/wmi/inc/wmi_unified_dcs_api.h new file mode 100644 index 0000000000..89a7894052 --- /dev/null +++ b/wmi/inc/wmi_unified_dcs_api.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: This file contains the API definitions for the Unified Wireless Module + * Interface (WMI) which are specific to DFS module. + */ + +#ifndef _WMI_UNIFIED_DCS_API_H_ +#define _WMI_UNIFIED_DCS_API_H_ + +#include +#include +#include +#include + +/** + * wmi_extract_dcs_interference_type() - extract dcs interference type + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @param: Pointer to hold dcs interference param + * + * This function gets called to extract dcs interference type from dcs FW event + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_dcs_interference_type( + void *wmi_hdl, + void *evt_buf, + struct wlan_host_dcs_interference_param *param); + +/** + * wmi_extract_dcs_im_tgt_stats() - extract dcs im target stats + * @wmi_handle: wmi handle + * @evt_buf: pointer to event buffer + * @wlan_stat: Pointer to hold wlan stats + * + * This function gets called to extract dcs im target stats from event + * + * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure + */ +QDF_STATUS wmi_extract_dcs_im_tgt_stats( + void *wmi_hdl, + void *evt_buf, + struct wlan_host_dcs_im_tgt_stats *wlan_stat); + +/** + * wmi_send_dcs_pdev_param() - send dcs pdev param + * @wmi_handle: wmi handle + * @pdev_idx: pdev id + * @is_target_pdev_id: target pdev_id or not + * @dcs_enable: value of dcs enable + * + * This functions gets called to send dcs pdev param + * + * Return: QDF_STATUS + */ +QDF_STATUS wmi_send_dcs_pdev_param(wmi_unified_t wmi_handle, + uint32_t pdev_idx, + bool is_target_pdev_id, + uint32_t dcs_enable); +#endif /* _WMI_UNIFIED_DCS_API_H_ */ diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index 940727f27b..764281cfda 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -878,10 +878,12 @@ struct suspend_params { * struct pdev_params - pdev set cmd parameter * @param_id: parameter id * @param_value: parameter value + * @is_target_pdev_id: indicate whether pdev_id is target pdev_id or not */ struct pdev_params { uint32_t param_id; uint32_t param_value; + bool is_target_pdev_id; }; /** diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 6ca4bca6c9..9a6229b602 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -69,6 +69,10 @@ #include #endif +#ifdef DCS_INTERFERENCE_DETECTION +#include +#endif + #define WMI_UNIFIED_MAX_EVENT 0x100 #ifdef WMI_EXT_DBG @@ -1433,6 +1437,17 @@ QDF_STATUS QDF_STATUS (*extract_wds_addr_event)(wmi_unified_t wmi_handle, void *evt_buf, uint16_t len, wds_addr_event_t *wds_ev); +#ifdef DCS_INTERFERENCE_DETECTION +QDF_STATUS (*extract_dcs_interference_type)( + wmi_unified_t wmi_handle, + void *evt_buf, + struct wlan_host_dcs_interference_param *param); + +QDF_STATUS (*extract_dcs_im_tgt_stats)( + wmi_unified_t wmi_handle, + void *evt_buf, + struct wlan_host_dcs_im_tgt_stats *wlan_stat); +#else QDF_STATUS (*extract_dcs_interference_type)(wmi_unified_t wmi_handle, void *evt_buf, struct wmi_host_dcs_interference_param *param); @@ -1441,6 +1456,7 @@ QDF_STATUS (*extract_dcs_cw_int)(wmi_unified_t wmi_handle, void *evt_buf, QDF_STATUS (*extract_dcs_im_tgt_stats)(wmi_unified_t wmi_handle, void *evt_buf, wmi_host_dcs_im_tgt_stats_t *wlan_stat); +#endif QDF_STATUS (*extract_fips_event_data)(wmi_unified_t wmi_handle, void *evt_buf, struct wmi_host_fips_event_param *param); @@ -2477,6 +2493,15 @@ wmi_interop_issues_ap_attach_tlv(struct wmi_unified *wmi_handle) } #endif +#ifdef DCS_INTERFERENCE_DETECTION +void wmi_dcs_attach_tlv(wmi_unified_t wmi_handle); +#else +static inline void +wmi_dcs_attach_tlv(struct wmi_unified *wmi_handle) +{ +} +#endif + #ifdef FEATURE_LFR_SUBNET_DETECTION void wmi_lfr_subnet_detection_attach_tlv(wmi_unified_t wmi_handle); #else diff --git a/wmi/src/wmi_unified_dcs_api.c b/wmi/src/wmi_unified_dcs_api.c new file mode 100644 index 0000000000..e4c83cc0ec --- /dev/null +++ b/wmi/src/wmi_unified_dcs_api.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: Implement API's specific to DCS component. + */ +#include + +QDF_STATUS wmi_extract_dcs_interference_type( + void *wmi_hdl, + void *evt_buf, + struct wlan_host_dcs_interference_param *param) +{ + wmi_unified_t wmi = (wmi_unified_t)wmi_hdl; + + if (wmi->ops->extract_dcs_interference_type) { + return wmi->ops->extract_dcs_interference_type(wmi, + evt_buf, + param); + } + return QDF_STATUS_E_FAILURE; +} + +QDF_STATUS wmi_extract_dcs_im_tgt_stats( + void *wmi_hdl, + void *evt_buf, + struct wlan_host_dcs_im_tgt_stats *wlan_stat) +{ + wmi_unified_t wmi_handle = (wmi_unified_t)wmi_hdl; + + if (wmi_handle->ops->extract_dcs_im_tgt_stats) { + return wmi_handle->ops->extract_dcs_im_tgt_stats(wmi_handle, + evt_buf, + wlan_stat); + } + return QDF_STATUS_E_FAILURE; +} + +#ifdef ENABLE_HOST_TO_TARGET_CONVERSION +QDF_STATUS wmi_send_dcs_pdev_param(wmi_unified_t wmi_handle, + uint32_t pdev_idx, + bool is_target_pdev_id, + uint32_t dcs_enable) +{ + struct pdev_params pparam; + + qdf_mem_zero(&pparam, sizeof(pparam)); + pparam.is_target_pdev_id = is_target_pdev_id; + pparam.param_id = wmi_pdev_param_dcs; + pparam.param_value = dcs_enable; + + return wmi_unified_pdev_param_send(wmi_handle, &pparam, pdev_idx); +} +#else +QDF_STATUS wmi_send_dcs_pdev_param(wmi_unified_t wmi_handle, + uint32_t pdev_idx, + bool is_target_pdev_id, + uint32_t dcs_enable) +{ + struct pdev_params pparam; + + qdf_mem_zero(&pparam, sizeof(pparam)); + pparam.is_target_pdev_id = is_target_pdev_id; + pparam.param_id = WMI_PDEV_PARAM_DCS; + pparam.param_value = dcs_enable; + + return wmi_unified_pdev_param_send(wmi_handle, &pparam, pdev_idx); +} +#endif diff --git a/wmi/src/wmi_unified_dcs_tlv.c b/wmi/src/wmi_unified_dcs_tlv.c new file mode 100644 index 0000000000..ef9a9c6ac8 --- /dev/null +++ b/wmi/src/wmi_unified_dcs_tlv.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2020, The Linux Foundation. All rights reserved. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "osdep.h" +#include "wmi.h" +#include "wmi_unified_priv.h" + +/** + * extract_dcs_interference_type_tlv() - extract dcs interference type + * from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param param: Pointer to hold dcs interference param + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_dcs_interference_type_tlv( + wmi_unified_t wmi_handle, + void *evt_buf, struct wlan_host_dcs_interference_param *param) +{ + WMI_DCS_INTERFERENCE_EVENTID_param_tlvs *param_buf; + + param_buf = (WMI_DCS_INTERFERENCE_EVENTID_param_tlvs *)evt_buf; + if (!param_buf) { + WMI_LOGE("Invalid dcs interference event buffer"); + return QDF_STATUS_E_INVAL; + } + + if (!param_buf->fixed_param) { + WMI_LOGE("Invalid fixed param"); + return QDF_STATUS_E_INVAL; + } + + param->interference_type = param_buf->fixed_param->interference_type; + /* Just support tlv currently */ + param->pdev_id = wmi_handle->ops->convert_target_pdev_id_to_host( + wmi_handle, + param_buf->fixed_param->pdev_id); + + return QDF_STATUS_SUCCESS; +} + +/** + * extract_dcs_im_tgt_stats_tlv() - extract dcs im target stats from event + * @wmi_handle: wmi handle + * @param evt_buf: pointer to event buffer + * @param wlan_stat: Pointer to hold wlan stats + * + * Return: 0 for success or error code + */ +static QDF_STATUS extract_dcs_im_tgt_stats_tlv( + wmi_unified_t wmi_handle, + void *evt_buf, + struct wlan_host_dcs_im_tgt_stats *wlan_stat) +{ + WMI_DCS_INTERFERENCE_EVENTID_param_tlvs *param_buf; + wlan_dcs_im_tgt_stats_t *ev; + + param_buf = (WMI_DCS_INTERFERENCE_EVENTID_param_tlvs *)evt_buf; + if (!param_buf) { + WMI_LOGE("Invalid dcs interference event buffer"); + return QDF_STATUS_E_INVAL; + } + + ev = param_buf->wlan_stat; + if (!ev) { + WMI_LOGE("Invalid wlan stat"); + return QDF_STATUS_E_INVAL; + } + + wlan_stat->reg_tsf32 = ev->reg_tsf32; + wlan_stat->last_ack_rssi = ev->last_ack_rssi; + wlan_stat->tx_waste_time = ev->tx_waste_time; + wlan_stat->rx_time = ev->rx_time; + wlan_stat->phyerr_cnt = ev->phyerr_cnt; + wlan_stat->mib_stats.listen_time = ev->listen_time; + wlan_stat->mib_stats.reg_tx_frame_cnt = ev->reg_tx_frame_cnt; + wlan_stat->mib_stats.reg_rx_frame_cnt = ev->reg_rx_frame_cnt; + wlan_stat->mib_stats.reg_rxclr_cnt = ev->reg_rxclr_cnt; + wlan_stat->mib_stats.reg_cycle_cnt = ev->reg_cycle_cnt; + wlan_stat->mib_stats.reg_rxclr_ext_cnt = ev->reg_rxclr_ext_cnt; + wlan_stat->mib_stats.reg_ofdm_phyerr_cnt = ev->reg_ofdm_phyerr_cnt; + wlan_stat->mib_stats.reg_cck_phyerr_cnt = ev->reg_cck_phyerr_cnt; + wlan_stat->chan_nf = ev->chan_nf; + wlan_stat->my_bss_rx_cycle_count = ev->my_bss_rx_cycle_count; + + return QDF_STATUS_SUCCESS; +} + +void wmi_dcs_attach_tlv(wmi_unified_t wmi_handle) +{ + struct wmi_ops *ops = wmi_handle->ops; + + ops->extract_dcs_interference_type = extract_dcs_interference_type_tlv; + ops->extract_dcs_im_tgt_stats = extract_dcs_im_tgt_stats_tlv; +} + diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index be44c70e26..8a97fef70c 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -1626,7 +1626,12 @@ send_pdev_param_cmd_tlv(wmi_unified_t wmi_handle, WMITLV_TAG_STRUC_wmi_pdev_set_param_cmd_fixed_param, WMITLV_GET_STRUCT_TLVLEN (wmi_pdev_set_param_cmd_fixed_param)); - cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( + if (param->is_target_pdev_id) + cmd->pdev_id = wmi_handle->ops->convert_host_pdev_id_to_target( + wmi_handle, + mac_id); + else + cmd->pdev_id = wmi_handle->ops->convert_pdev_id_host_to_target( wmi_handle, mac_id); cmd->param_id = pdev_param; @@ -14165,6 +14170,7 @@ void wmi_tlv_attach(wmi_unified_t wmi_handle) wmi_nan_attach_tlv(wmi_handle); wmi_p2p_attach_tlv(wmi_handle); wmi_interop_issues_ap_attach_tlv(wmi_handle); + wmi_dcs_attach_tlv(wmi_handle); wmi_roam_attach_tlv(wmi_handle); wmi_concurrency_attach_tlv(wmi_handle); wmi_pmo_attach_tlv(wmi_handle);