Эх сурвалжийг харах

qcacmn: Add dcs component

Add dcs component to implement interference detection algorithm
and dynamic channel selection frequency control.

Change-Id: Ia201d77e77feb9de3aff03d6e389d4891dde118e
CRs-Fixed: 2594837
hqu 5 жил өмнө
parent
commit
fed4bfb049

+ 7 - 1
cfg/inc/cfg_converged.h

@@ -33,6 +33,11 @@
 #define CFG_GREEN_AP_ALL
 #endif
 #include <cfg_spectral.h>
+#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 */
 

+ 86 - 0
init_deinit/dispatcher/src/dispatcher_init_deinit.c

@@ -76,6 +76,10 @@
 #include <wlan_coex_utils_api.h>
 #endif
 
+#ifdef DCS_INTERFERENCE_DETECTION
+#include <wlan_dcs_init_deinit_api.h>
+#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;
 

+ 2 - 0
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;

+ 2 - 0
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,

+ 20 - 0
target_if/core/src/target_if_main.c

@@ -84,6 +84,10 @@
 #include <target_if_coex.h>
 #endif
 
+#ifdef DCS_INTERFERENCE_DETECTION
+#include <target_if_dcs.h>
+#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);

+ 70 - 0
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 <target_if.h>
+#include <wlan_lmac_if_def.h>
+
+/**
+ * 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__ */
+

+ 197 - 0
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 <wmi_unified_api.h>
+#include <wmi_unified_priv.h>
+#include <wmi_unified_dcs_api.h>
+#include <init_deinit_lmac.h>
+#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;
+}
+

+ 2 - 0
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,
 };
 

+ 3 - 0
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];

+ 727 - 0
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 <target_if_dcs.h>
+#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;
+}

+ 227 - 0
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 <wmi_unified_param.h>
+#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_ */

+ 309 - 0
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"
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#define CFG_DCS_ENABLE CFG_INI_UINT(\
+		"gEnableDcs",\
+		0, 3, 0,\
+		CFG_VALUE_OR_DEFAULT, "Enable DCS")
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#define CFG_DCS_DEBUG CFG_INI_UINT(\
+		"dcs_debug",\
+		0, 2, 0,\
+		CFG_VALUE_OR_DEFAULT,\
+		"dcs debug trace level")
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#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")
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#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")
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#define CFG_DCS_PHY_ERR_PENALTY CFG_INI_UINT(\
+		"dcs_phy_err_penalty",\
+		0, 0xFFFFFFFF, 500,\
+		CFG_VALUE_OR_DEFAULT,\
+		"dcs phy error penalty")
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#define CFG_DCS_PHY_ERR_THRESHOLD CFG_INI_UINT(\
+		"dcs_phy_err_threshold",\
+		0, 0xFFFFFFFF, 300,\
+		CFG_VALUE_OR_DEFAULT,\
+		"dcs phy error threshold")
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#define CFG_DCS_USER_MAX_CU CFG_INI_UINT(\
+		"user_max_cu",\
+		0, 0xFFFFFFFF, 50,\
+		CFG_VALUE_OR_DEFAULT,\
+		"dcs tx channel utilization")
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#define CFG_DCS_RADAR_ERR_THRESHOLD CFG_INI_UINT(\
+		"dcs_radar_err_threshold",\
+		0, 0xFFFFFFFF, 1000,\
+		CFG_VALUE_OR_DEFAULT,\
+		"dcs radar error threshold")
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#define CFG_DCS_INTFR_DETECTION_THRESHOLD CFG_INI_UINT(\
+		"dcs_intfr_detection_threshold",\
+		0, 0xFFFFFFFF, 6,\
+		CFG_VALUE_OR_DEFAULT,\
+		"dcs interference detection threshold")
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#define CFG_DCS_INTFR_DETECTION_WINDOW CFG_INI_UINT(\
+		"dcs_intfr_detection_window",\
+		0, 0xFFFFFFFF, 10,\
+		CFG_VALUE_OR_DEFAULT,\
+		"dcs interference sampling window")
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#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")
+
+/*
+ * <ini>
+ * 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
+ *
+ * </ini>
+ */
+#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 */

+ 91 - 0
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 <qdf_types.h>
+#include <qdf_status.h>
+#include <wlan_objmgr_cmn.h>
+
+/**
+ * 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__ */
+

+ 86 - 0
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

+ 50 - 0
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 <wlan_objmgr_cmn.h>
+#include <wlan_dcs_public_structs.h>
+
+/**
+ * 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__ */

+ 120 - 0
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 <qdf_status.h>
+#include <wlan_objmgr_pdev_obj.h>
+
+/**
+ * @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_ */

+ 210 - 0
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;
+}

+ 30 - 0
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);
+}

+ 93 - 0
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;
+}

+ 37 - 0
umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h

@@ -82,6 +82,10 @@ struct dbr_module_config;
 #include <wlan_vdev_mgr_tgt_if_tx_defs.h>
 #include <wlan_vdev_mgr_tgt_if_rx_defs.h>
 
+#ifdef DCS_INTERFERENCE_DETECTION
+#include <wlan_dcs_tgt_api.h>
+#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

+ 23 - 0
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);

+ 75 - 0
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 <qdf_status.h>
+#include <wmi_unified_api.h>
+#include <wmi_unified_priv.h>
+#include <wlan_objmgr_vdev_obj.h>
+
+/**
+ * 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_ */

+ 2 - 0
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;
 };
 
 /**

+ 25 - 0
wmi/inc/wmi_unified_priv.h

@@ -69,6 +69,10 @@
 #include <wmi_unified_cfr_param.h>
 #endif
 
+#ifdef DCS_INTERFERENCE_DETECTION
+#include <wlan_dcs_public_structs.h>
+#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

+ 82 - 0
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 <wmi_unified_dcs_api.h>
+
+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

+ 110 - 0
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;
+}
+

+ 7 - 1
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);