qcacmn: Moving spectral module to cmn_dev
As part of second phase of Spectral Analysis(SA)
convergence [WIN & MCL], spectral module code is being moved to cmn_dev.
Also includes fixes for checkpatch.
CRs-Fixed: 2146231
Change-Id: I939509193786b0bd2cbd5f1af64d4a94739a2af5
diff --git a/spectral/Kbuild b/spectral/Kbuild
new file mode 100644
index 0000000..eac23f4
--- /dev/null
+++ b/spectral/Kbuild
@@ -0,0 +1,205 @@
+ifeq ($(obj),)
+obj := .
+endif
+
+DEPTH := ../..
+
+ifeq ($(strip ${QCA_PARTNER_MAKE_F_SUPPORT}),1)
+export QCA_PARTNER_MAKE_F_INC=1
+endif
+
+include $(obj)/$(DEPTH)/os/linux/Makefile-linux.common
+
+INCS += -I$(HAL) -I$(HAL)/$(OS) -I$(ATH) -I$(ATH_RATE) -I$(ATH_PKTLOG) -I$(WLAN) -I$(IF_WLAN) -I$(ATH_SPECTRAL) -I$(ATHEROSPATH) -I$(obj)/$(DEPTH)/../../apps/spectral/common
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/inc -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/obj_mgr/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/cmn_defs/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/scan/dispatcher/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/cmn_defs/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/global_umac_dispatcher/lmac_if/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/scheduler/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/global_lmac_if/inc
+INCS += -I$(obj)/$(DEPTH)/umac/scan
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/mgmt_txrx/dispatcher/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/regulatory/dispatcher/inc
+INCS += -I$(obj)/$(DEPTH)/umac/son/dispatcher/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/dfs/dispatcher/inc
+
+ifeq ($(WLAN_CONV_CRYPTO_SUPPORTED), 1)
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/crypto/inc
+endif
+
+#Start of offload related deifines
+HOST_CMN_CONVG_SRC := $(DEPTH)/cmn_dev
+HOST_CMN_CONVG_HIF_SRC := $(DEPTH)/cmn_dev/hif/src
+HOST_CMN_CONVG_HIF_INC1 := $(DEPTH)/cmn_dev/hif
+HOST_CMN_CONVG_HTC_INC := $(DEPTH)/cmn_dev/htc
+HOST_CMN_CONVG_DP_INC := $(DEPTH)/cmn_dev/dp/wifi3.0
+HOST_CMN_CONVG_CFG_INC := $(DEPTH)/cmn_dev/wlan_cfg
+HOST_CMN_CONVG_HAL_INC := $(DEPTH)/cmn_dev/hal/inc
+HOST_CMN_CONVG_HAL_WIFI_INC := $(DEPTH)/cmn_dev/hal/wifi3.0
+
+INCS += -I$(obj)/$(DEPTH)/include -I$(obj)/$(DEPTH)/umac/include \
+ -I$(obj)/$(DEPTH)/umac/if_lmac -I$(obj)/$(DEPTH)/umac/crypto \
+ -I$(obj)/$(DEPTH)/umac/scan -I$(obj)/$(DEPTH)/umac/resmgr \
+ -I$(obj)/$(DEPTH)/umac/pm -I$(obj)/$(DEPTH)/umac/txrx \
+ -I$(obj)/$(DEPTH)/umac/acs -I$(obj)/$(DEPTH)/umac/txbf \
+ -I$(obj)/$(DEPTH)/umac/wnm \
+ -I$(obj)/$(DEPTH)/umac/tdls \
+ -I$(obj)/$(DEPTH)/umac/rpt_placement \
+ -I$(obj)/$(DEPTH)/umac/wifipos \
+ -I$(obj)/$(DEPTH)/umac/wds -I$(obj)/$(DEPTH)/umac/ique \
+ -I$(obj)/$(DEPTH)/hal -I$(obj)/$(DEPTH)/lmac/ath_dev \
+ -I$(obj)/$(DEPTH)/hal/$(OS) \
+ -I$(obj)/$(DEPTH)/umac/vi_dbg \
+ -I$(obj)/$(DEPTH)/umac/smart_antenna \
+ -I$(obj)/$(DEPTH)/umac/smart_ant \
+ -I$(obj)/$(DEPTH)/umac/ald \
+ -I$(obj)/$(DEPTH)/lmac/ath_pktlog \
+ -I$(obj)/$(DEPTH)/lmac/ratectrl \
+ -I$(obj)/$(DEPTH)/os/linux/mem/ \
+ -I$(obj)/$(DEPTH)/umac/base \
+ -I$(obj)/$(DEPTH)/qca_ol \
+ -I$(obj)/$(DEPTH)/cmn_dev/qdf/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/qdf/linux/src \
+ -I$(obj)/$(DEPTH)/cmn_dev/hif \
+ -I$(obj)/$(DEPTH)/cmn_dev/hif/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/hif/src \
+ -I$(obj)/$(DEPTH)/cmn_dev/hif/src/ce \
+ -I$(obj)/$(DEPTH)/cmn_dev/hif/src/pcie \
+ -I$(obj)/$(DEPTH)/cmn_dev/hif/src/snoc \
+ -I$(obj)/$(DEPTH)/cmn_dev/hif/src/dispatcher \
+ -I$(obj)/$(DEPTH)/cmn_dev/pld_stub/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/hal/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/hal/wifi3.0 \
+ -I$(obj)/$(DEPTH)/cmn_dev/dp/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/dp/wifi3.0 \
+ -I$(obj)/$(DEPTH)/cmn_dev/wlan_cfg \
+ -I$(obj)/$(HOST_CMN_CONVG_SRC)/htc \
+ -I$(obj)/$(DEPTH)/cmn_dev/wmi/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/obj_mgr/inc \
+ -I$(obj)/$(HOST_CMN_CONVG_SRC)/scheduler/inc \
+ -I$(obj)/$(HOST_CMN_CONVG_SRC)/init_deinit/dispatcher/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/umac/global_umac_dispatcher/lmac_if/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/mgmt_txrx/dispatcher/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/target_if/init_deinit/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/global_lmac_if/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/os_if/linux \
+ -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/cmn_defs/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/target_if/core/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/umac/scan/dispatcher/inc \
+ -I$(obj)/$(DEPTH)/umac/scan \
+ -I$(obj)/$(DEPTH)/cmn_dev/ol_if \
+ -I$(obj)/$(DEPTH)/cmn_dev/target_if/scan/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/serialization/core/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/umac/regulatory/dispatcher/inc \
+ -I$(obj)/$(DEPTH)/cmn_dev/target_if/regulatory/inc \
+
+PERF_PWR_OFFLOAD_INC += -I$(PERF_PWR_OFFLOAD_DIR_PATH)/wlan/include \
+ -I$(PERF_PWR_OFFLOAD_DIR_PATH)/wlan/ath_pktlog/include \
+ -I$(PERF_PWR_OFFLOAD_DIR_PATH)/htt/include \
+ -I$(PERF_PWR_OFFLOAD_DIR_PATH)/wlan/txrx/include \
+ -I$(PERF_PWR_OFFLOAD_DIR_PATH)/include \
+ -I$(PERF_PWR_OFFLOAD_DIR_PATH)/include \
+ -I$(PERF_PWR_OFFLOAD_DIR_PATH)/hif/pci \
+ -I$(PERF_PWR_OFFLOAD_DIR_PATH)/hif/pci/linux \
+ -I$(PERF_PWR_OFFLOAD_DIR_PATH)/os/linux/include \
+ -I$(PERF_PWR_OFFLOAD_DIR_PATH)/wlan/regdmn \
+ -I$(PERF_PWR_OFFLOAD_DIR_PATH)/wlan/lmac_offload_if \
+ -I$(HOST_CMN_CONVG_HIF_INC1)/inc \
+ -I$(HOST_CMN_CONVG_HIF_INC1)/src \
+ -I$(HOST_CMN_CONVG_HIF_INC1)/src/pcie \
+ -I$(HOST_CMN_CONVG_HIF_INC1)/src/snoc \
+ -I$(HOST_CMN_CONVG_SRC)/pld_stub/inc \
+ -I$(HOST_CMN_CONVG_HIF_SRC)/ce \
+ -I$(HOST_CMN_CONVG_HTC_INC) \
+ -I$(HOST_CMN_CONVG_CFG_INC) \
+ -I$(HOST_CMN_CONVG_DP_INC) \
+ -I$(HOST_CMN_CONVG_HAL_INC) \
+ -I$(HOST_CMN_CONVG_HAL_WIFI_INC) \
+ -I$(PERF_PWR_OFFLOAD_WMI_SRC)/inc \
+ -I$(obj)/$(DEPTH)/offload/extra_include
+
+INCS += $(PERF_PWR_OFFLOAD_INC)
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/target_if/spectral
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/wmi/inc
+INCS += -I$(PERF_PWR_OFFLOAD_DIR_PATH)/hw/include
+#end of offload related defines
+
+#Start of Legacy spectral related defines
+INCS += -I$(HAL) -I$(HAL)/$(OS) -I$(ATH) -I$(ATH_RATE) -I$(ATH_PKTLOG) -I$(WLAN) -I$(IF_WLAN) -I$(ATH_SPECTRAL) -I$(ATHEROSPATH) -I$(obj)/$(DEPTH)/../../apps/spectral/common
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/inc -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/obj_mgr/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/cmn_defs/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/scan/dispatcher/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/cmn_defs/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/global_umac_dispatcher/lmac_if/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/scheduler/inc
+INCS += -I$(obj)/$(DEPTH)/umac/scan
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/cmn_services/mgmt_txrx/dispatcher/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/regulatory/dispatcher/inc
+INCS += -I$(obj)/$(DEPTH)/cmn_dev/umac/dfs/dispatcher/inc
+
+SPECTRAL_DA_OBJS := $(DEPTH)/lmac/spectral/spectral.o \
+ $(DEPTH)/lmac/spectral/spectral_netlink.o \
+ $(DEPTH)/lmac/spectral/spectral_cmds.o \
+ $(DEPTH)/lmac/spectral/spectral_process_data.o \
+ $(DEPTH)/lmac/spectral/spectral_phyerr.o
+#End of legacy spectral defines
+
+ifeq ($(QCA_AIRTIME_FAIRNESS), 1)
+ccflags-y+= -DWLAN_ATF_ENABLE
+INCS += -I$(obj)/$(DEPTH)/umac/airtime_fairness/dispatcher/inc
+endif
+
+ifeq ($(UNIFIED_SMARTANTENNA), 1)
+ccflags-y+= -DWLAN_SA_API_ENABLE
+INCS += -I$(obj)/$(DEPTH)/umac/sa_api/dispatcher/inc
+endif
+
+ifeq ($(strip ${QCA_DFS_COMPONENT_ENABLE}),1)
+ccflags-y+= -DDFS_COMPONENT_ENABLE
+endif
+
+obj-m += qca_spectral.o
+
+ccflags-y+= $(INCS) $(COPTS) -DSPECTRAL_USE_NETLINK_SOCKETS=1 -DWLAN_SPECTRAL_ENABLE=1
+
+ifeq ($(strip ${QCA_PARTNER_MAKE_F_SUPPORT}),1)
+MOD_CFLAGS = -D"KBUILD_STR(s)=\#s" -D"KBUILD_BASENAME=KBUILD_STR(qca_spectral.mod)" -D"KBUILD_MODNAME=KBUILD_STR(qca_spectral)"
+endif
+
+INCS += -I$(obj)/$(DEPTH)/spectral/dispatcher/inc
+
+SPECTRAL_TIF_OBJS += $(DEPTH)/cmn_dev/target_if/spectral/target_if_spectral.o \
+ $(DEPTH)/cmn_dev/target_if/spectral/target_if_spectral_netlink.o \
+ $(DEPTH)/cmn_dev/target_if/spectral/target_if_spectral_phyerr.o \
+ $(DEPTH)/cmn_dev/target_if/spectral/target_if_spectral_sim.o
+
+SPECTRAL_CMN_OBJS += core/spectral_direct_attach.o \
+ core/spectral_offload.o \
+ core/spectral_common.o \
+ dispatcher/src/wlan_spectral_utils_api.o \
+ dispatcher/src/wlan_spectral_ucfg_api.o \
+ dispatcher/src/wlan_spectral_tgt_api.o \
+ core/spectral_module.o
+
+qca_spectral-objs += ${SPECTRAL_CMN_OBJS} \
+ ${SPECTRAL_TIF_OBJS} \
+ ${SPECTRAL_DA_OBJS}
+
+ifeq ($(strip ${QCA_PARTNER_MAKE_F_SUPPORT}),1)
+all: qca_spectral.ko
+
+qca_spectral.mod.o: qca_spectral.mod.c
+ ${CC} -c -o $@ ${ccflags-y} ${MOD_CFLAGS} $<
+
+qca_spectral.o: ${qca_spectral-objs}
+ $(LD) -m elf32btsmip -r -o qca_spectral.o $(qca_spectral-objs)
+ $(KERNELPATH)/scripts/mod/modpost qca_spectral.o
+
+qca_spectral.ko: qca_spectral.o qca_spectral.mod.o
+ $(LD) $(LDOPTS) -o qca_spectral.ko qca_spectral.o qca_spectral.mod.o
+
+%.o: %.c
+ ${CC} -c -o $@ ${ccflags-y} $<
+endif
diff --git a/spectral/core/spectral_cmn_api_i.h b/spectral/core/spectral_cmn_api_i.h
new file mode 100644
index 0000000..4436c0d
--- /dev/null
+++ b/spectral/core/spectral_cmn_api_i.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SPECTRAL_CMN_API_I_H_
+#define _SPECTRAL_CMN_API_I_H_
+
+#include "spectral_defs_i.h"
+
+/**
+ * wlan_spectral_psoc_obj_create_handler(): handler for psoc object create
+ * @psoc: reference to global psoc object
+ * @arg: reference to argument provided during registration of handler
+ *
+ * This is a handler to indicate psoc object created. Hence spectral_context
+ * object can be created and attached to psoc component list.
+ *
+ * Return: QDF_STATUS_SUCCESS on success
+ * QDF_STATUS_E_FAILURE if psoc is null
+ * QDF_STATUS_E_NOMEM on failure of spectral object allocation
+ */
+QDF_STATUS wlan_spectral_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc,
+ void *arg);
+
+/**
+ * wlan_spectral_psoc_obj_destroy_handler(): handler for psoc object delete
+ * @psoc: reference to global psoc object
+ * @arg: reference to argument provided during registration of handler
+ *
+ * This is a handler to indicate psoc object going to be deleted.
+ * Hence spectral_context object can be detached from psoc component list.
+ * Then spectral_context object can be deleted.
+ *
+ * Return: QDF_STATUS_SUCCESS on success
+ * QDF_STATUS_E_FAILURE on failure
+ */
+QDF_STATUS wlan_spectral_psoc_obj_destroy_handler(struct wlan_objmgr_psoc *psoc,
+ void *arg);
+
+/**
+ * wlan_spectral_pdev_obj_create_handler(): handler for pdev object create
+ * @pdev: reference to global pdev object
+ * @arg: reference to argument provided during registration of handler
+ *
+ * This is a handler to indicate pdev object created. Hence pdev specific
+ * spectral object can be created and attached to pdev component list.
+ *
+ * Return: QDF_STATUS_SUCCESS on success
+ * QDF_STATUS_E_FAILURE if pdev is null
+ * QDF_STATUS_E_NOMEM on failure of spectral object allocation
+ */
+QDF_STATUS wlan_spectral_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev,
+ void *arg);
+
+/**
+ * wlan_spectral_pdev_obj_destroy_handler(): handler for pdev object delete
+ * @pdev: reference to global pdev object
+ * @arg: reference to argument provided during registration of handler
+ *
+ * This is a handler to indicate pdev object going to be deleted.
+ * Hence pdev specific spectral object can be detached from pdev component list.
+ * Then pdev_spectral object can be deleted.
+ *
+ * Return: QDF_STATUS_SUCCESS on success
+ * QDF_STATUS_E_FAILURE on failure
+ */
+QDF_STATUS wlan_spectral_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev,
+ void *arg);
+
+/**
+ * spectral_control_cmn(): common handler for demultiplexing requests from
+ * higher layer
+ * @pdev: reference to global pdev object
+ * @id: spectral config command id
+ * @indata: reference to input data
+ * @insize: input data size
+ * @outdata: reference to output data
+ * @outsize: reference to output data size
+ *
+ * This function processes the spectral config command
+ * and appropriate handlers are invoked.
+ *
+ * Return: 0 success else failure
+ */
+int spectral_control_cmn(
+ struct wlan_objmgr_pdev *pdev,
+ u_int id,
+ void *indata,
+ u_int32_t insize,
+ void *outdata, u_int32_t *outsize);
+
+/**
+ * spectral_get_spectral_ctx_from_pdev() - API to get spectral context object
+ * from pdev
+ * @pdev : Reference to pdev global object
+ *
+ * This API used to get spectral context object from global pdev reference.
+ * Null check should be done before invoking this inline function.
+ *
+ * Return : Reference to spectral_context object
+ */
+static inline
+struct spectral_context *spectral_get_spectral_ctx_from_pdev(
+ struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+ struct spectral_context *sc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ if (psoc) {
+ sc = wlan_objmgr_psoc_get_comp_private_obj(
+ psoc,
+ WLAN_UMAC_COMP_SPECTRAL);
+ }
+
+ return sc;
+}
+
+#endif /* _SPECTRAL_CMN_API_I_H_*/
+
diff --git a/spectral/core/spectral_common.c b/spectral/core/spectral_common.c
new file mode 100644
index 0000000..c3e2303
--- /dev/null
+++ b/spectral/core/spectral_common.c
@@ -0,0 +1,562 @@
+/*
+ * Copyright (c) 2011,2017 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 "spectral_cmn_api_i.h"
+#include "spectral_da_api_i.h"
+#include "spectral_ol_api_i.h"
+#include <qdf_mem.h>
+#include <qdf_types.h>
+#include <osif_private.h>
+#include <wlan_spectral_public_structs.h>
+#include <wlan_mlme_dispatcher.h>
+
+/**
+ * spectral_get_vdev() - Get pointer to vdev to be used for Spectral
+ * operations
+ * @pdev: Pointer to pdev
+ *
+ * Spectral operates on pdev. However, in order to retrieve some WLAN
+ * properties, a vdev is required. To facilitate this, the function returns the
+ * first vdev in our pdev. The caller should release the reference to the vdev
+ * once it is done using it. Additionally, the caller should ensure it has a
+ * reference to the pdev at the time of calling this function, and should
+ * release the pdev reference either after this function returns or at a later
+ * time when the caller is done using pdev.
+ * TODO:
+ * - If the framework later provides an API to obtain the first active
+ * vdev, then it would be preferable to use this API.
+ * - Use a common get_vdev() handler for core and target_if using Rx ops. This
+ * is deferred till details emerge on framework providing API to get first
+ * active vdev.
+ *
+ * Return: Pointer to vdev on success, NULL on failure
+ */
+struct wlan_objmgr_vdev*
+spectral_get_vdev(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_vdev *vdev = NULL;
+
+ qdf_assert_always(pdev);
+
+ vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, 0, WLAN_SPECTRAL_ID);
+
+ if (!vdev) {
+ qdf_print("%s: Unable to get first vdev of pdev.\n", __func__);
+ return NULL;
+ }
+
+ return vdev;
+}
+
+int spectral_control_cmn(
+ struct wlan_objmgr_pdev *pdev,
+ u_int id,
+ void *indata,
+ u_int32_t insize,
+ void *outdata, u_int32_t *outsize)
+{
+ int error = 0;
+ int temp_debug;
+ struct spectral_config sp_out;
+ struct spectral_config *sp_in;
+ struct spectral_config *spectralparams;
+ struct spectral_context *sc;
+ struct wlan_objmgr_vdev *vdev = NULL;
+ u_int8_t vdev_rxchainmask = 0;
+
+ if (!pdev) {
+ spectral_err("PDEV is NULL!\n");
+ error = -EINVAL;
+ goto bad;
+ }
+ sc = spectral_get_spectral_ctx_from_pdev(pdev);
+ if (!sc) {
+ spectral_err("atf context is NULL!\n");
+ error = -EINVAL;
+ goto bad;
+ }
+
+ switch (id) {
+ case SPECTRAL_SET_CONFIG:
+ {
+ if (insize < sizeof(struct spectral_config) || !indata) {
+ error = -EINVAL;
+ break;
+ }
+ sp_in = (struct spectral_config *)indata;
+ if (sp_in->ss_count != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_SCAN_COUNT,
+ sp_in->ss_count))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_fft_period != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_FFT_PERIOD,
+ sp_in->ss_fft_period))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_period != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_SCAN_PERIOD,
+ sp_in->ss_period))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_short_report != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_SHORT_REPORT,
+ (u_int32_t)(sp_in->ss_short_report ? 1 : 0)))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_spectral_pri != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_SPECT_PRI,
+ (u_int32_t)(sp_in->ss_spectral_pri)))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_fft_size != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_FFT_SIZE,
+ sp_in->ss_fft_size))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_gc_ena != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_GC_ENA,
+ sp_in->ss_gc_ena))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_restart_ena != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_RESTART_ENA,
+ sp_in->ss_restart_ena))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_noise_floor_ref != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_NOISE_FLOOR_REF,
+ sp_in->ss_noise_floor_ref))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_init_delay != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_INIT_DELAY,
+ sp_in->ss_init_delay))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_nb_tone_thr != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_NB_TONE_THR,
+ sp_in->ss_nb_tone_thr))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_str_bin_thr != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_STR_BIN_THR,
+ sp_in->ss_str_bin_thr))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_wb_rpt_mode != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_WB_RPT_MODE,
+ sp_in->ss_wb_rpt_mode))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_rssi_rpt_mode != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_RSSI_RPT_MODE,
+ sp_in->ss_rssi_rpt_mode))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_rssi_thr != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_RSSI_THR,
+ sp_in->ss_rssi_thr))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_pwr_format != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_PWR_FORMAT,
+ sp_in->ss_pwr_format))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_rpt_mode != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_RPT_MODE,
+ sp_in->ss_rpt_mode))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_bin_scale != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_BIN_SCALE,
+ sp_in->ss_bin_scale))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_dBm_adj != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ if (!sc->sptrlc_set_spectral_config(
+ pdev,
+ SPECTRAL_PARAM_DBM_ADJ,
+ sp_in->ss_dBm_adj))
+ error = -EINVAL;
+ }
+
+ if (sp_in->ss_chn_mask != SPECTRAL_PHYERR_PARAM_NOVAL) {
+ /* Check if any of the inactive Rx antenna chains is
+ * set active in
+ * spectral chainmask
+ */
+ vdev = spectral_get_vdev(pdev);
+ if (!vdev) {
+ error = -ENOENT;
+ break;
+ }
+
+ vdev_rxchainmask = wlan_vdev_mlme_get_rxchainmask(vdev);
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
+
+ if (!(sp_in->ss_chn_mask & vdev_rxchainmask)) {
+ qdf_print("Invalid Spectral Chainmask - "
+ "Inactive Rx antenna chain cannot "
+ "be an active spectral chain\n");
+ error = -EINVAL;
+ break;
+ } else if (!sc->sptrlc_set_spectral_config(pdev,
+ SPECTRAL_PARAM_CHN_MASK, sp_in->ss_chn_mask)) {
+ error = -EINVAL;
+ }
+ }
+ }
+ break;
+
+ case SPECTRAL_GET_CONFIG:
+ {
+ if (!outdata || !outsize || (*outsize < sizeof(
+ struct spectral_config))) {
+ error = -EINVAL;
+ break;
+ }
+ *outsize = sizeof(struct spectral_config);
+ sc->sptrlc_get_spectral_config(pdev, &sp_out);
+ spectralparams = (struct spectral_config *)outdata;
+ spectralparams->ss_fft_period = sp_out.ss_fft_period;
+ spectralparams->ss_period = sp_out.ss_period;
+ spectralparams->ss_count = sp_out.ss_count;
+ spectralparams->ss_short_report = sp_out.ss_short_report;
+ spectralparams->ss_spectral_pri = sp_out.ss_spectral_pri;
+ spectralparams->ss_fft_size = sp_out.ss_fft_size;
+ spectralparams->ss_gc_ena = sp_out.ss_gc_ena;
+ spectralparams->ss_restart_ena = sp_out.ss_restart_ena;
+ spectralparams->ss_noise_floor_ref = sp_out.ss_noise_floor_ref;
+ spectralparams->ss_init_delay = sp_out.ss_init_delay;
+ spectralparams->ss_nb_tone_thr = sp_out.ss_nb_tone_thr;
+ spectralparams->ss_str_bin_thr = sp_out.ss_str_bin_thr;
+ spectralparams->ss_wb_rpt_mode = sp_out.ss_wb_rpt_mode;
+ spectralparams->ss_rssi_rpt_mode = sp_out.ss_rssi_rpt_mode;
+ spectralparams->ss_rssi_thr = sp_out.ss_rssi_thr;
+ spectralparams->ss_pwr_format = sp_out.ss_pwr_format;
+ spectralparams->ss_rpt_mode = sp_out.ss_rpt_mode;
+ spectralparams->ss_bin_scale = sp_out.ss_bin_scale;
+ spectralparams->ss_dBm_adj = sp_out.ss_dBm_adj;
+ spectralparams->ss_chn_mask = sp_out.ss_chn_mask;
+ }
+ break;
+
+ case SPECTRAL_IS_ACTIVE:
+ {
+ if (!outdata || !outsize || *outsize < sizeof(u_int32_t)) {
+ error = -EINVAL;
+ break;
+ }
+ *outsize = sizeof(u_int32_t);
+ *((u_int32_t *)outdata) =
+ (u_int32_t)sc->sptrlc_is_spectral_active(pdev);
+ }
+ break;
+
+ case SPECTRAL_IS_ENABLED:
+ {
+ if (!outdata || !outsize || *outsize < sizeof(u_int32_t)) {
+ error = -EINVAL;
+ break;
+ }
+ *outsize = sizeof(u_int32_t);
+ *((u_int32_t *)outdata) =
+ (u_int32_t)sc->sptrlc_is_spectral_enabled(pdev);
+ }
+ break;
+
+ case SPECTRAL_SET_DEBUG_LEVEL:
+ {
+ if (insize < sizeof(u_int32_t) || !indata) {
+ error = -EINVAL;
+ break;
+ }
+ temp_debug = *(u_int32_t *)indata;
+ sc->sptrlc_set_debug_level(pdev, temp_debug);
+ }
+ break;
+
+ case SPECTRAL_ACTIVATE_SCAN:
+ {
+ sc->sptrlc_start_spectral_scan(pdev);
+ }
+ break;
+
+ case SPECTRAL_STOP_SCAN:
+ {
+ sc->sptrlc_stop_spectral_scan(pdev);
+ }
+ break;
+
+ case SPECTRAL_GET_CAPABILITY_INFO:
+ {
+ if (!outdata || !outsize ||
+ *outsize < sizeof(struct spectral_caps)) {
+ error = -EINVAL;
+ break;
+ }
+ *outsize = sizeof(struct spectral_caps);
+ sc->sptrlc_get_spectral_capinfo(pdev, outdata);
+ }
+ break;
+
+ case SPECTRAL_GET_DIAG_STATS:
+ {
+ if (!outdata || !outsize ||
+ (*outsize < sizeof(struct spectral_diag_stats))) {
+ error = -EINVAL;
+ break;
+ }
+ *outsize = sizeof(struct spectral_diag_stats);
+ sc->sptrlc_get_spectral_diagstats(pdev, outdata);
+ }
+ break;
+
+ case SPECTRAL_GET_CHAN_WIDTH:
+ {
+ u_int32_t chan_width;
+
+ vdev = spectral_get_vdev(pdev);
+ if (!vdev)
+ return -ENOENT;
+
+ chan_width = wlan_vdev_get_ch_width(vdev);
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
+
+ if (!outdata || !outsize ||
+ *outsize < sizeof(chan_width)) {
+ error = -EINVAL;
+ break;
+ }
+ *outsize = sizeof(chan_width);
+ *((u_int32_t *)outdata) = (u_int32_t)chan_width;
+ }
+ break;
+
+ default:
+ error = -EINVAL;
+ break;
+ }
+
+bad:
+ return error;
+}
+
+static void spectral_ctx_deinit(struct spectral_context *sc)
+{
+ if (sc) {
+ sc->sptrlc_ucfg_phyerr_config = NULL;
+ sc->sptrlc_pdev_spectral_init = NULL;
+ sc->sptrlc_pdev_spectral_deinit = NULL;
+ sc->sptrlc_set_spectral_config = NULL;
+ sc->sptrlc_get_spectral_config = NULL;
+ sc->sptrlc_start_spectral_scan = NULL;
+ sc->sptrlc_stop_spectral_scan = NULL;
+ sc->sptrlc_is_spectral_active = NULL;
+ sc->sptrlc_is_spectral_enabled = NULL;
+ sc->sptrlc_set_debug_level = NULL;
+ sc->sptrlc_get_debug_level = NULL;
+ sc->sptrlc_get_spectral_capinfo = NULL;
+ sc->sptrlc_get_spectral_diagstats = NULL;
+ }
+}
+
+QDF_STATUS
+wlan_spectral_psoc_obj_create_handler(struct wlan_objmgr_psoc *psoc, void *arg)
+{
+ struct spectral_context *sc = NULL;
+
+ if (!psoc) {
+ spectral_err("PSOC is NULL\n");
+ return QDF_STATUS_E_FAILURE;
+ }
+ sc = (struct spectral_context *)qdf_mem_malloc(
+ sizeof(struct spectral_context));
+ if (!sc) {
+ spectral_err("Failed to allocate spectral_ctx object\n");
+ return QDF_STATUS_E_NOMEM;
+ }
+ qdf_mem_zero(sc, sizeof(struct spectral_context));
+ sc->psoc_obj = psoc;
+ if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_DA)
+ spectral_ctx_init_da(sc);
+ else if (wlan_objmgr_psoc_get_dev_type(psoc) == WLAN_DEV_OL)
+ spectral_ctx_init_ol(sc);
+ wlan_objmgr_psoc_component_obj_attach(psoc, WLAN_UMAC_COMP_SPECTRAL,
+ (void *)sc, QDF_STATUS_SUCCESS);
+
+ return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_spectral_psoc_obj_destroy_handler(
+ struct wlan_objmgr_psoc *psoc,
+ void *arg)
+{
+ struct spectral_context *sc = NULL;
+
+ if (!psoc) {
+ spectral_err("PSOC is NULL\n");
+ return QDF_STATUS_E_FAILURE;
+ }
+ sc = wlan_objmgr_psoc_get_comp_private_obj(
+ psoc,
+ WLAN_UMAC_COMP_SPECTRAL);
+ if (sc) {
+ wlan_objmgr_psoc_component_obj_detach(
+ psoc,
+ WLAN_UMAC_COMP_SPECTRAL,
+ (void *)sc);
+ /* Deinitilise function pointers from spectral context */
+ spectral_ctx_deinit(sc);
+ qdf_mem_free(sc);
+ }
+
+ return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS
+wlan_spectral_pdev_obj_create_handler(struct wlan_objmgr_pdev *pdev, void *arg)
+{
+ struct pdev_spectral *ps = NULL;
+ struct spectral_context *sc = NULL;
+ void *target_handle = NULL;
+
+ if (!pdev) {
+ spectral_err("PDEV is NULL\n");
+ return QDF_STATUS_E_FAILURE;
+ }
+ ps = (struct pdev_spectral *)qdf_mem_malloc(
+ sizeof(struct pdev_spectral));
+ if (!ps) {
+ spectral_err("Failed to allocate pdev_spectral object\n");
+ return QDF_STATUS_E_NOMEM;
+ }
+ sc = spectral_get_spectral_ctx_from_pdev(pdev);
+ if (!sc) {
+ spectral_err("Spectral context is NULL!\n");
+ goto cleanup;
+ }
+
+ qdf_mem_zero(ps, sizeof(struct pdev_spectral));
+ ps->psptrl_pdev = pdev;
+ if (sc->sptrlc_pdev_spectral_init) {
+ target_handle = sc->sptrlc_pdev_spectral_init(pdev);
+ if (!target_handle) {
+ spectral_err("Spectral lmac object is NULL!\n");
+ goto cleanup;
+ }
+ ps->psptrl_target_handle = target_handle;
+ }
+ wlan_objmgr_pdev_component_obj_attach(pdev, WLAN_UMAC_COMP_SPECTRAL,
+ (void *)ps, QDF_STATUS_SUCCESS);
+
+ return QDF_STATUS_SUCCESS;
+cleanup:
+ qdf_mem_free(ps);
+ return QDF_STATUS_E_FAILURE;
+}
+
+QDF_STATUS
+wlan_spectral_pdev_obj_destroy_handler(struct wlan_objmgr_pdev *pdev, void *arg)
+{
+ struct pdev_spectral *ps = NULL;
+ struct spectral_context *sc = NULL;
+
+ if (!pdev) {
+ spectral_err("PDEV is NULL\n");
+ return QDF_STATUS_E_FAILURE;
+ }
+ sc = spectral_get_spectral_ctx_from_pdev(pdev);
+ if (!sc) {
+ spectral_err("Spectral context is NULL!\n");
+ return QDF_STATUS_E_FAILURE;
+ }
+ ps = wlan_objmgr_pdev_get_comp_private_obj(
+ pdev,
+ WLAN_UMAC_COMP_SPECTRAL);
+ if (ps) {
+ if (sc->sptrlc_pdev_spectral_deinit)
+ sc->sptrlc_pdev_spectral_deinit(pdev);
+ ps->psptrl_target_handle = NULL;
+ wlan_objmgr_pdev_component_obj_detach(
+ pdev,
+ WLAN_UMAC_COMP_SPECTRAL,
+ (void *)ps);
+ qdf_mem_free(ps);
+ }
+
+ return QDF_STATUS_SUCCESS;
+}
+
diff --git a/spectral/core/spectral_da_api_i.h b/spectral/core/spectral_da_api_i.h
new file mode 100644
index 0000000..c0dca87
--- /dev/null
+++ b/spectral/core/spectral_da_api_i.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SPECTRAL_DA_API_I_H_
+#define _SPECTRAL_DA_API_I_H_
+
+#include "spectral_defs_i.h"
+
+/**
+ * spectral_ctx_init_da() - Internal function to initialise spectral context
+ * with direct attach specific functions
+ * @sc : spectral context
+ *
+ * Return : void
+ */
+void spectral_ctx_init_da(struct spectral_context *sc);
+
+#endif /* _SPECTRAL_DA_API_I_H_ */
diff --git a/spectral/core/spectral_defs_i.h b/spectral/core/spectral_defs_i.h
new file mode 100644
index 0000000..6c6bd7b
--- /dev/null
+++ b/spectral/core/spectral_defs_i.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SPECTRAL_DEFS_I_H_
+#define _SPECTRAL_DEFS_I_H_
+
+#include <wlan_objmgr_cmn.h>
+#include <wlan_objmgr_global_obj.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <qdf_list.h>
+#include <qdf_timer.h>
+#include <qdf_util.h>
+#include <wlan_spectral_public_structs.h>
+#include <if_athioctl.h>
+#include <spectral_ioctl.h>
+
+#define spectral_log(level, args...) \
+QDF_PRINT_INFO(QDF_PRINT_IDX_SHARED, QDF_MODULE_ID_SPECTRAL, level, ## args)
+
+#define spectral_logfl(level, format, args...) \
+ spectral_log(level, FL(format), ## args)
+
+#define spectral_fatal(format, args...) \
+ spectral_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args)
+#define spectral_err(format, args...) \
+ spectral_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args)
+#define spectral_warn(format, args...) \
+ spectral_logfl(QDF_TRACE_LEVEL_WARN, format, ## args)
+#define spectral_info(format, args...) \
+ spectral_logfl(QDF_TRACE_LEVEL_INFO, format, ## args)
+#define spectral_debug(format, args...) \
+ spectral_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args)
+
+/**
+ * struct pdev_spectral - Radio specific spectral object
+ * @psptrl_pdev: Back-pointer to struct wlan_objmgr_pdev
+ * @psptrl_nl_sock: Spectral Netlink socket for sending samples to
+ * applications
+ * @psptrl_target_handle: reference to spectral lmac object
+ */
+struct pdev_spectral {
+ struct wlan_objmgr_pdev *psptrl_pdev;
+ struct sock *psptrl_nl_sock;
+ void *psptrl_target_handle;
+};
+
+/**
+ * struct spectral_context : spectral global context
+ *
+ * @psoc_obj: Reference to psoc global object
+ *
+ * Call back functions to invoke independent of OL/DA
+ * @sptrlc_ucfg_phyerr_config: ucfg handler for phyerr
+ * @sptrlc_pdev_spectral_init: Init spectral
+ * @sptrlc_pdev_spectral_deinit: Deinit spectral
+ * @sptrlc_set_spectral_config: Set spectral configurations
+ * @sptrlc_get_spectral_config: Get spectral configurations
+ * @sptrlc_start_spectral_scan: Start spectral scan
+ * @sptrlc_stop_spectral_scan: Stop spectral scan
+ * @sptrlc_is_spectral_active: Check if spectral scan is active
+ * @sptrlc_is_spectral_enabled: Check if spectral is enabled
+ * @sptrlc_set_debug_level: Set debug level
+ * @sptrlc_get_debug_level: Get debug level
+ * @sptrlc_get_spectral_capinfo: Get spectral capability info
+ * @sptrlc_get_spectral_diagstats: Get spectral diag status
+ */
+struct spectral_context {
+ struct wlan_objmgr_psoc *psoc_obj;
+ int (*sptrlc_spectral_control)(struct wlan_objmgr_pdev *pdev, u_int id,
+ void *indata, u_int32_t insize,
+ void *outdata, u_int32_t *outsize);
+ int (*sptrlc_ucfg_phyerr_config)(struct wlan_objmgr_pdev *pdev,
+ struct ath_diag *ad);
+ void * (*sptrlc_pdev_spectral_init)(struct wlan_objmgr_pdev *pdev);
+ void (*sptrlc_pdev_spectral_deinit)(struct wlan_objmgr_pdev *pdev);
+ int (*sptrlc_set_spectral_config)(
+ struct wlan_objmgr_pdev *pdev,
+ const u_int32_t threshtype, const u_int32_t value);
+ void (*sptrlc_get_spectral_config)(
+ struct wlan_objmgr_pdev *pdev,
+ struct spectral_config *sptrl_config);
+ int (*sptrlc_start_spectral_scan)(struct wlan_objmgr_pdev *pdev);
+ void (*sptrlc_stop_spectral_scan)(struct wlan_objmgr_pdev *pdev);
+ bool (*sptrlc_is_spectral_active)(struct wlan_objmgr_pdev *pdev);
+ bool (*sptrlc_is_spectral_enabled)(struct wlan_objmgr_pdev *pdev);
+ int (*sptrlc_set_debug_level)(struct wlan_objmgr_pdev *pdev,
+ u_int32_t debug_level);
+ u_int32_t (*sptrlc_get_debug_level)(struct wlan_objmgr_pdev *pdev);
+ void (*sptrlc_get_spectral_capinfo)(struct wlan_objmgr_pdev *pdev,
+ void *outdata);
+ void (*sptrlc_get_spectral_diagstats)(struct wlan_objmgr_pdev *pdev,
+ void *outdata);
+};
+
+#endif /* _SPECTRAL_DEFS_I_H_ */
+
diff --git a/spectral/core/spectral_direct_attach.c b/spectral/core/spectral_direct_attach.c
new file mode 100644
index 0000000..58ab4d7
--- /dev/null
+++ b/spectral/core/spectral_direct_attach.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2011,2017 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 "spectral_cmn_api_i.h"
+
+int spectral_control_da(struct wlan_objmgr_pdev *pdev, u_int id, void *indata,
+ u_int32_t insize, void *outdata, u_int32_t *outsize)
+{
+ struct spectral_context *sc;
+ int error = 0;
+
+ if (!pdev) {
+ spectral_err("PDEV is NULL!\n");
+ return -EPERM;
+ }
+ sc = spectral_get_spectral_ctx_from_pdev(pdev);
+ if (!sc) {
+ spectral_err("spectral context is NULL!\n");
+ return -EPERM;
+ }
+ switch (id) {
+#if ATH_SUPPORT_RAW_ADC_CAPTURE
+ case SPECTRAL_ADC_ENABLE_TEST_ADDAC_MODE:
+ error = spectral_enter_raw_capture_mode(dev, indata);
+ break;
+ case SPECTRAL_ADC_DISABLE_TEST_ADDAC_MODE:
+ error = spectral_exit_raw_capture_mode(dev);
+ break;
+ case SPECTRAL_ADC_RETRIEVE_DATA:
+ error = spectral_retrieve_raw_capture(dev, outdata, outsize);
+ break;
+#endif
+ default:
+ error = spectral_control_cmn(
+ pdev,
+ id,
+ indata,
+ insize,
+ outdata,
+ outsize);
+ break;
+ }
+ return error;
+}
+
+static void *pdev_spectral_init_da(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_pdev_spectral_init(
+ pdev);
+}
+
+static void pdev_spectral_deinit_da(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_pdev_spectral_deinit(pdev);
+}
+
+static int set_spectral_config_da(
+ struct wlan_objmgr_pdev *pdev,
+ const u_int32_t threshtype, const u_int32_t value)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_set_spectral_config(
+ pdev,
+ threshtype,
+ value);
+}
+
+static void get_spectral_config_da(struct wlan_objmgr_pdev *pdev,
+ struct spectral_config *sptrl_config)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_get_spectral_config(pdev,
+ sptrl_config);
+}
+
+static int start_spectral_scan_da(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_start_spectral_scan(
+ pdev);
+}
+
+static void stop_spectral_scan_da(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_stop_spectral_scan(pdev);
+}
+
+static bool is_spectral_active_da(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_is_spectral_active(
+ pdev);
+}
+
+static bool is_spectral_enabled_da(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_is_spectral_enabled(
+ pdev);
+}
+
+static int set_debug_level_da(struct wlan_objmgr_pdev *pdev,
+ u_int32_t debug_level)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_set_debug_level(pdev,
+ debug_level);
+}
+
+static u_int32_t get_debug_level_da(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_get_debug_level(pdev);
+}
+
+static void get_spectral_capinfo_da(struct wlan_objmgr_pdev *pdev,
+ void *outdata)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_get_spectral_capinfo(
+ pdev,
+ outdata);
+}
+
+static void get_spectral_diagstats_da(struct wlan_objmgr_pdev *pdev,
+ void *outdata)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_get_spectral_diagstats(
+ pdev,
+ outdata);
+}
+
+void spectral_ctx_init_da(struct spectral_context *sc)
+{
+ if (!sc) {
+ spectral_err("spectral context is null!\n");
+ return;
+ }
+ sc->sptrlc_spectral_control = spectral_control_da;
+ sc->sptrlc_pdev_spectral_init = pdev_spectral_init_da;
+ sc->sptrlc_pdev_spectral_deinit = pdev_spectral_deinit_da;
+ sc->sptrlc_set_spectral_config = set_spectral_config_da;
+ sc->sptrlc_get_spectral_config = get_spectral_config_da;
+ sc->sptrlc_start_spectral_scan = start_spectral_scan_da;
+ sc->sptrlc_stop_spectral_scan = stop_spectral_scan_da;
+ sc->sptrlc_is_spectral_active = is_spectral_active_da;
+ sc->sptrlc_is_spectral_enabled = is_spectral_enabled_da;
+ sc->sptrlc_set_debug_level = set_debug_level_da;
+ sc->sptrlc_get_debug_level = get_debug_level_da;
+ sc->sptrlc_get_spectral_capinfo = get_spectral_capinfo_da;
+ sc->sptrlc_get_spectral_diagstats = get_spectral_diagstats_da;
+}
+
diff --git a/spectral/core/spectral_module.c b/spectral/core/spectral_module.c
new file mode 100644
index 0000000..ce42e63
--- /dev/null
+++ b/spectral/core/spectral_module.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2011,2017 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<linux/module.h>
+#include <wlan_spectral_utils_api.h>
+#include <qdf_types.h>
+#include<wlan_global_lmac_if_api.h>
+
+/**
+ * spectral_init_module() - Initialize Spectral module
+ *
+ * Return: None
+ */
+static int __init
+spectral_init_module(void)
+{
+ qdf_print("qca_spectral module loaded\n");
+ wlan_spectral_init();
+ /* register spectral rxops*/
+ wlan_lmac_if_sptrl_set_rx_ops_register_cb(
+ wlan_lmac_if_sptrl_register_rx_ops);
+ return 0;
+}
+
+/**
+ * spectral_exit_module() - De-initialize and exit Spectral module
+ *
+ * Return: None
+ */
+static void __exit
+spectral_exit_module(void)
+{
+ wlan_spectral_deinit();
+ qdf_print("qca_spectral module unloaded\n");
+}
+
+module_init(spectral_init_module);
+module_exit(spectral_exit_module);
+
diff --git a/spectral/core/spectral_offload.c b/spectral/core/spectral_offload.c
new file mode 100644
index 0000000..b4a352a
--- /dev/null
+++ b/spectral/core/spectral_offload.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2017 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 "spectral_cmn_api_i.h"
+
+int spectral_control_ol(
+ struct wlan_objmgr_pdev *pdev,
+ u_int id,
+ void *indata,
+ u_int32_t insize,
+ void *outdata, u_int32_t *outsize)
+{
+ struct spectral_context *sc;
+
+ if (!pdev) {
+ spectral_err("PDEV is NULL!\n");
+ return -EPERM;
+ }
+ sc = spectral_get_spectral_ctx_from_pdev(pdev);
+ if (!sc) {
+ spectral_err("spectral context is NULL!\n");
+ return -EPERM;
+ }
+ return spectral_control_cmn(pdev, id, indata, insize, outdata, outsize);
+}
+
+static void *pdev_spectral_init_ol(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_pdev_spectral_init(
+ pdev);
+}
+
+static void pdev_spectral_deinit_ol(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_pdev_spectral_deinit(pdev);
+}
+
+static int set_spectral_config_ol(
+ struct wlan_objmgr_pdev *pdev,
+ const u_int32_t threshtype, const u_int32_t value)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_set_spectral_config(
+ pdev,
+ threshtype, value);
+}
+
+static void get_spectral_config_ol(struct wlan_objmgr_pdev *pdev,
+ struct spectral_config *sptrl_config)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_get_spectral_config(pdev,
+ sptrl_config);
+}
+
+static int start_spectral_scan_ol(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_start_spectral_scan(
+ pdev);
+}
+
+static void stop_spectral_scan_ol(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_stop_spectral_scan(pdev);
+}
+
+static bool is_spectral_active_ol(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_is_spectral_active(
+ pdev);
+}
+
+static bool is_spectral_enabled_ol(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_is_spectral_enabled(
+ pdev);
+}
+
+static int set_debug_level_ol(struct wlan_objmgr_pdev *pdev,
+ u_int32_t debug_level)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_set_debug_level(pdev,
+ debug_level);
+}
+
+static u_int32_t get_debug_level_ol(struct wlan_objmgr_pdev *pdev)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_get_debug_level(pdev);
+}
+
+static void get_spectral_capinfo_ol(struct wlan_objmgr_pdev *pdev,
+ void *outdata)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_get_spectral_capinfo(
+ pdev,
+ outdata);
+}
+
+static void get_spectral_diagstats_ol(struct wlan_objmgr_pdev *pdev,
+ void *outdata)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ return psoc->soc_cb.tx_ops.sptrl_tx_ops.sptrlto_get_spectral_diagstats(
+ pdev,
+ outdata);
+}
+
+void spectral_ctx_init_ol(struct spectral_context *sc)
+{
+ if (!sc) {
+ spectral_err("spectral context is null!\n");
+ return;
+ }
+ sc->sptrlc_spectral_control = spectral_control_ol;
+ sc->sptrlc_pdev_spectral_init = pdev_spectral_init_ol;
+ sc->sptrlc_pdev_spectral_deinit = pdev_spectral_deinit_ol;
+ sc->sptrlc_set_spectral_config = set_spectral_config_ol;
+ sc->sptrlc_get_spectral_config = get_spectral_config_ol;
+ sc->sptrlc_start_spectral_scan = start_spectral_scan_ol;
+ sc->sptrlc_stop_spectral_scan = stop_spectral_scan_ol;
+ sc->sptrlc_is_spectral_active = is_spectral_active_ol;
+ sc->sptrlc_is_spectral_enabled = is_spectral_enabled_ol;
+ sc->sptrlc_set_debug_level = set_debug_level_ol;
+ sc->sptrlc_get_debug_level = get_debug_level_ol;
+ sc->sptrlc_get_spectral_capinfo = get_spectral_capinfo_ol;
+ sc->sptrlc_get_spectral_diagstats = get_spectral_diagstats_ol;
+}
+
diff --git a/spectral/core/spectral_ol_api_i.h b/spectral/core/spectral_ol_api_i.h
new file mode 100644
index 0000000..6541654
--- /dev/null
+++ b/spectral/core/spectral_ol_api_i.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SPECTRAL_OL_API_I_H_
+#define _SPECTRAL_OL_API_I_H_
+
+#include "spectral_defs_i.h"
+
+/**
+ * spectral_ctx_init_ol() - Internal function to initialise spectral context
+ * with offload specific functions
+ * @sc : spectral context
+ *
+ * Return : void
+ */
+void spectral_ctx_init_ol(struct spectral_context *sc);
+
+#endif /* _SPECTRAL_OL_API_I_H_ */
diff --git a/spectral/dispatcher/inc/wlan_spectral_public_structs.h b/spectral/dispatcher/inc/wlan_spectral_public_structs.h
new file mode 100644
index 0000000..c6fe1d8
--- /dev/null
+++ b/spectral/dispatcher/inc/wlan_spectral_public_structs.h
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2011,2017 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 <qdf_types.h>
+#include "wlan_dfs_ioctl.h"
+
+#ifndef _WLAN_SPECTRAL_PUBLIC_STRUCTS_H_
+#define _WLAN_SPECTRAL_PUBLIC_STRUCTS_H_
+
+#ifdef WIN32
+#pragma pack(push, spectral, 1)
+#define __ATTRIB_PACKED
+#else
+#ifndef __ATTRIB_PACKED
+#define __ATTRIB_PACKED __attribute__ ((packed))
+#endif
+#endif
+
+#ifndef AH_MAX_CHAINS
+#define AH_MAX_CHAINS 3
+#endif
+
+#define MAX_NUM_CHANNELS 255
+#define MAX_SPECTRAL_CHAINS 3
+#define MAX_NUM_BINS 520
+#define SPECTRAL_PHYERR_PARAM_NOVAL 65535
+/* 5 categories x (lower + upper) bands */
+#define MAX_INTERF 10
+
+/* ioctl parameter types */
+#define SPECTRAL_PARAM_FFT_PERIOD (1)
+#define SPECTRAL_PARAM_SCAN_PERIOD (2)
+#define SPECTRAL_PARAM_SCAN_COUNT (3)
+#define SPECTRAL_PARAM_SHORT_REPORT (4)
+#define SPECTRAL_PARAM_SPECT_PRI (5)
+#define SPECTRAL_PARAM_FFT_SIZE (6)
+#define SPECTRAL_PARAM_GC_ENA (7)
+#define SPECTRAL_PARAM_RESTART_ENA (8)
+#define SPECTRAL_PARAM_NOISE_FLOOR_REF (9)
+#define SPECTRAL_PARAM_INIT_DELAY (10)
+#define SPECTRAL_PARAM_NB_TONE_THR (11)
+#define SPECTRAL_PARAM_STR_BIN_THR (12)
+#define SPECTRAL_PARAM_WB_RPT_MODE (13)
+#define SPECTRAL_PARAM_RSSI_RPT_MODE (14)
+#define SPECTRAL_PARAM_RSSI_THR (15)
+#define SPECTRAL_PARAM_PWR_FORMAT (16)
+#define SPECTRAL_PARAM_RPT_MODE (17)
+#define SPECTRAL_PARAM_BIN_SCALE (18)
+#define SPECTRAL_PARAM_DBM_ADJ (19)
+#define SPECTRAL_PARAM_CHN_MASK (20)
+#define SPECTRAL_PARAM_ACTIVE (21)
+#define SPECTRAL_PARAM_STOP (22)
+#define SPECTRAL_PARAM_ENABLE (23)
+
+#ifdef ATH_SPECTRAL_USE_EMU_DEFAULTS
+/* Use defaults from emulation */
+#define SPECTRAL_SCAN_ACTIVE_DEFAULT (0x0)
+#define SPECTRAL_SCAN_ENABLE_DEFAULT (0x0)
+#define SPECTRAL_SCAN_COUNT_DEFAULT (0x0)
+#define SPECTRAL_SCAN_PERIOD_DEFAULT (250)
+#define SPECTRAL_SCAN_PRIORITY_DEFAULT (0x1)
+#define SPECTRAL_SCAN_FFT_SIZE_DEFAULT (0x7)
+#define SPECTRAL_SCAN_GC_ENA_DEFAULT (0x1)
+#define SPECTRAL_SCAN_RESTART_ENA_DEFAULT (0x0)
+#define SPECTRAL_SCAN_NOISE_FLOOR_REF_DEFAULT (0xa0)
+#define SPECTRAL_SCAN_INIT_DELAY_DEFAULT (0x50)
+#define SPECTRAL_SCAN_NB_TONE_THR_DEFAULT (0xc)
+#define SPECTRAL_SCAN_STR_BIN_THR_DEFAULT (0x7)
+#define SPECTRAL_SCAN_WB_RPT_MODE_DEFAULT (0x0)
+#define SPECTRAL_SCAN_RSSI_RPT_MODE_DEFAULT (0x1)
+#define SPECTRAL_SCAN_RSSI_THR_DEFAULT (0xf)
+#define SPECTRAL_SCAN_PWR_FORMAT_DEFAULT (0x1)
+#define SPECTRAL_SCAN_RPT_MODE_DEFAULT (0x2)
+#define SPECTRAL_SCAN_BIN_SCALE_DEFAULT (0x1)
+#define SPECTRAL_SCAN_DBM_ADJ_DEFAULT (0x0)
+#define SPECTRAL_SCAN_CHN_MASK_DEFAULT (0x1)
+#else
+/* Static default values for spectral state and configuration.
+ * These definitions should be treated as temporary. Ideally,
+ * we should get the defaults from firmware - this will be discussed.
+ *
+ * Use defaults from Spectral Hardware Micro-Architecture
+ * document (v1.0)
+ */
+#define SPECTRAL_SCAN_ACTIVE_DEFAULT (0)
+#define SPECTRAL_SCAN_ENABLE_DEFAULT (0)
+#define SPECTRAL_SCAN_COUNT_DEFAULT (0)
+#define SPECTRAL_SCAN_PERIOD_DEFAULT (35)
+#define SPECTRAL_SCAN_PRIORITY_DEFAULT (1)
+#define SPECTRAL_SCAN_FFT_SIZE_DEFAULT (7)
+#define SPECTRAL_SCAN_GC_ENA_DEFAULT (1)
+#define SPECTRAL_SCAN_RESTART_ENA_DEFAULT (0)
+#define SPECTRAL_SCAN_NOISE_FLOOR_REF_DEFAULT (-96)
+#define SPECTRAL_SCAN_INIT_DELAY_DEFAULT (80)
+#define SPECTRAL_SCAN_NB_TONE_THR_DEFAULT (12)
+#define SPECTRAL_SCAN_STR_BIN_THR_DEFAULT (8)
+#define SPECTRAL_SCAN_WB_RPT_MODE_DEFAULT (0)
+#define SPECTRAL_SCAN_RSSI_RPT_MODE_DEFAULT (0)
+#define SPECTRAL_SCAN_RSSI_THR_DEFAULT (0xf0)
+#define SPECTRAL_SCAN_PWR_FORMAT_DEFAULT (0)
+#define SPECTRAL_SCAN_RPT_MODE_DEFAULT (2)
+#define SPECTRAL_SCAN_BIN_SCALE_DEFAULT (1)
+#define SPECTRAL_SCAN_DBM_ADJ_DEFAULT (1)
+#define SPECTRAL_SCAN_CHN_MASK_DEFAULT (1)
+#endif /* ATH_SPECTRAL_USE_EMU_DEFAULTS */
+
+/* The below two definitions apply only to pre-11ac chipsets */
+#define SPECTRAL_SCAN_SHORT_REPORT_DEFAULT (1)
+#define SPECTRAL_SCAN_FFT_PERIOD_DEFAULT (1)
+
+/**
+ * enum spectral_debug - Spectral debug level
+ * @ATH_DEBUG_SPECTRAL: Minimal SPECTRAL debug
+ * @ATH_DEBUG_SPECTRAL1: Normal SPECTRAL debug
+ * @ATH_DEBUG_SPECTRAL2: Maximal SPECTRAL debug
+ * @ATH_DEBUG_SPECTRAL3: Matched filterID display
+ * @ATH_DEBUG_SPECTRAL4: One time dump of FFT report
+ */
+enum spectral_debug {
+ ATH_DEBUG_SPECTRAL = 0x00000100,
+ ATH_DEBUG_SPECTRAL1 = 0x00000200,
+ ATH_DEBUG_SPECTRAL2 = 0x00000400,
+ ATH_DEBUG_SPECTRAL3 = 0x00000800,
+ ATH_DEBUG_SPECTRAL4 = 0x00001000,
+};
+
+/**
+ * enum SPECTRAL_CAPABILITY_TYPE - Spectral capability type
+ * @SPECTRAL_CAP_PHYDIAG: Phydiag capability
+ * @SPECTRAL_CAP_RADAR: Radar detection capability
+ * @SPECTRAL_CAP_SPECTRAL_SCAN: Spectral capability
+ * @SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN: Advanced spectral capability
+ */
+typedef enum {
+ SPECTRAL_CAP_PHYDIAG,
+ SPECTRAL_CAP_RADAR,
+ SPECTRAL_CAP_SPECTRAL_SCAN,
+ SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN,
+} SPECTRAL_CAPABILITY_TYPE;
+
+/**
+ * struct spectral_chan_stats - channel status info
+ * @cycle_count: Cycle count
+ * @channel_load: Channel load
+ * @per: Period
+ * @noisefloor: Noise floor
+ * @comp_usablity: Computed usability
+ * @maxregpower: Maximum allowed regulatory power
+ * @comp_usablity_sec80: Computed usability of secondary 80 Mhz
+ * @maxregpower_sec80: Max regulatory power of secondary 80 Mhz
+ */
+struct spectral_chan_stats {
+ int cycle_count;
+ int channel_load;
+ int per;
+ int noisefloor;
+ u_int16_t comp_usablity;
+ int8_t maxregpower;
+ u_int16_t comp_usablity_sec80;
+ int8_t maxregpower_sec80;
+};
+
+/**
+ * struct spectral_diag_stats - spectral diag stats
+ * @spectral_mismatch: Spectral TLV signature mismatches
+ * @spectral_sec80_sfft_insufflen: Insufficient length when parsing for
+ * Secondary 80 Search FFT report
+ * @spectral_no_sec80_sfft: Secondary 80 Search FFT report
+ * TLV not found
+ * @spectral_vhtseg1id_mismatch: VHT Operation Segment 1 ID
+ * mismatches in Search FFT report
+ * @spectral_vhtseg2id_mismatch: VHT Operation Segment 2 ID
+ * mismatches in Search FFT report
+ */
+struct spectral_diag_stats {
+ u_int64_t spectral_mismatch;
+ u_int64_t spectral_sec80_sfft_insufflen;
+ u_int64_t spectral_no_sec80_sfft;
+ u_int64_t spectral_vhtseg1id_mismatch;
+ u_int64_t spectral_vhtseg2id_mismatch;
+};
+
+/**
+ * struct spectral_caps - Spectral capabilities structure
+ * @phydiag_cap: Phydiag capability
+ * @radar_cap: Radar detection capability
+ * @spectral_cap: Spectral capability
+ * @advncd_spectral_cap: Advanced spectral capability
+ */
+struct spectral_caps {
+ u_int8_t phydiag_cap;
+ u_int8_t radar_cap;
+ u_int8_t spectral_cap;
+ u_int8_t advncd_spectral_cap;
+};
+
+/**
+ * struct spectral_config
+ * @ss_fft_period: Skip interval for FFT reports
+ * @ss_period: Spectral scan period
+ * @ss_count: # of reports to return from ss_active
+ * @ss_short_report: Set to report only 1 set of FFT results
+ * @radar_bin_thresh_sel: Select threshold to classify strong bin for FFT
+ * @ss_spectral_pri: Priority, and are we doing a noise power cal ?
+ * @ss_fft_size: Defines the number of FFT data points to compute,
+ * defined as a log index num_fft_pts =
+ * 2^ss_fft_size
+ * @ss_gc_ena: Set, to enable targeted gain change before
+ * starting the spectral scan FFT
+ * @ss_restart_ena: Set, to enable abort of receive frames when in high
+ * priority and a spectral scan is queued
+ * @ss_noise_floor_ref: Noise floor reference number (signed) for the
+ * calculation of bin power (dBm) Though stored as an
+ * unsigned this should be treated as a signed 8-bit int.
+ * @ss_init_delay: Disallow spectral scan triggers after tx/rx packets
+ * by setting this delay value to roughly SIFS time
+ * period or greater Delay timer count in units of 0.25us
+ * @ss_nb_tone_thr: Number of strong bins (inclusive) per sub-channel,
+ * below which a signal is declared a narrowband tone
+ * @ss_str_bin_thr: Bin/max_bin ratio threshold over which a bin is
+ * declared strong (for spectral scan bandwidth analysis)
+ * @ss_wb_rpt_mode: Set this bit to report spectral scans as EXT_BLOCKER
+ * (phy_error=36), if none of the sub-channels are
+ * deemed narrowband
+ * @ss_rssi_rpt_mode: Set this bit to report spectral scans as EXT_BLOCKER
+ * (phy_error=36), if the ADC RSSI is below the
+ * threshold ss_rssi_thr
+ * @ss_rssi_thr: ADC RSSI must be greater than or equal to this
+ * threshold (signed Db) to ensure spectral scan
+ * reporting with normal phy error codes (please see
+ * ss_rssi_rpt_mode above).Though stored as an unsigned
+ * value, this should be treated as a signed 8-bit int
+ * @ss_pwr_format: Format of frequency bin magnitude for spectral scan
+ * triggered FFTs 0: linear magnitude
+ * 1: log magnitude (20*log10(lin_mag), 1/2 dB step size)
+ * @ss_rpt_mode: Format of per-FFT reports to software for spectral
+ * scan triggered FFTs
+ * 0: No FFT report (only pulse end summary)
+ * 1: 2-dword summary of metrics for each completed FFT
+ * 2: 2-dword summary + 1x-oversampled bins(in-band) per
+ * FFT
+ * 3: 2-dword summary + 2x-oversampled bins (all) per FFT
+ * @ss_bin_scale: Number of LSBs to shift out to scale the FFT bins
+ * for spectral scan triggered FFTs
+ * @ss_dBm_adj: Set (with ss_pwr_format=1), to report bin
+ * magnitudes
+ * converted to dBm power using the noisefloor
+ * calibration results
+ * @ss_chn_mask: Per chain enable mask to select input ADC for search
+ * FFT
+ * @ss_nf_cal: nf calibrated values for ctl+ext
+ * @ss_nf_pwr: nf pwr values for ctl+ext
+ * @ss_nf_temp_data: temperature data taken during nf scan
+ */
+struct spectral_config {
+ u_int16_t ss_fft_period;
+ u_int16_t ss_period;
+ u_int16_t ss_count;
+ u_int16_t ss_short_report;
+ u_int8_t radar_bin_thresh_sel;
+ u_int16_t ss_spectral_pri;
+ u_int16_t ss_fft_size;
+ u_int16_t ss_gc_ena;
+ u_int16_t ss_restart_ena;
+ u_int16_t ss_noise_floor_ref;
+ u_int16_t ss_init_delay;
+ u_int16_t ss_nb_tone_thr;
+ u_int16_t ss_str_bin_thr;
+ u_int16_t ss_wb_rpt_mode;
+ u_int16_t ss_rssi_rpt_mode;
+ u_int16_t ss_rssi_thr;
+ u_int16_t ss_pwr_format;
+ u_int16_t ss_rpt_mode;
+ u_int16_t ss_bin_scale;
+ u_int16_t ss_dBm_adj;
+ u_int16_t ss_chn_mask;
+ int8_t ss_nf_cal[AH_MAX_CHAINS * 2];
+ int8_t ss_nf_pwr[AH_MAX_CHAINS * 2];
+ int32_t ss_nf_temp_data;
+};
+
+/**
+ * struct spectral_caps - Spectral capabilities structure
+ * @phydiag_cap: Phydiag capability
+ * @radar_cap: Radar detection capability
+ * @spectral_cap: Spectral capability
+ * @advncd_spectral_cap: Advanced spectral capability
+ */
+typedef enum _dcs_int_type {
+ SPECTRAL_DCS_INT_NONE,
+ SPECTRAL_DCS_INT_CW,
+ SPECTRAL_DCS_INT_WIFI
+} DCS_INT_TYPE;
+
+/**
+ * struct INTERF_RSP - Interference record
+ * @interf_type: eINTERF_TYPE giving type of interference
+ * @interf_min_freq: Minimum frequency in MHz at which interference has been
+ * found
+ * @interf_max_freq: Maximum frequency in MHz at which interference has been
+ * found
+ * @advncd_spectral_cap: Advanced spectral capability
+ */
+struct INTERF_RSP {
+ u_int8_t interf_type;
+ u_int16_t interf_min_freq;
+ u_int16_t interf_max_freq;
+} __ATTRIB_PACKED;
+
+/**
+ * struct INTERF_SRC_RSP - List of interference sources
+ * @count: Number of interference records
+ * @interf: Array of interference records
+ */
+struct INTERF_SRC_RSP {
+ u_int16_t count;
+ struct INTERF_RSP interf[MAX_INTERF];
+} __ATTRIB_PACKED;
+
+/**
+ * struct spectral_classifier_params -
+ * @spectral_20_40_mode: Is AP in 20/40 mode?
+ * @spectral_dc_index: DC index
+ * @spectral_dc_in_mhz: DC in MHz
+ * @upper_chan_in_mhz: Upper channel in MHz
+ * @lower_chan_in_mhz: Lower channel in MHz
+ */
+typedef struct spectral_classifier_params {
+ int spectral_20_40_mode;
+ int spectral_dc_index;
+ int spectral_dc_in_mhz;
+ int upper_chan_in_mhz;
+ int lower_chan_in_mhz;
+} __ATTRIB_PACKED SPECTRAL_CLASSIFIER_PARAMS;
+
+/**
+ * struct spectral_samp_data - Spectral Analysis Messaging Protocol Data format
+ * @spectral_data_len: Indicates the bin size
+ * @spectral_data_len_sec80: Indicates the bin size for secondary 80 segment
+ * @spectral_rssi: Indicates RSSI
+ * @spectral_rssi_sec80: Indicates RSSI for secondary 80 segment
+ * @spectral_combined_rssi: Indicates combined RSSI from all antennas
+ * @spectral_upper_rssi: Indicates RSSI of upper band
+ * @spectral_lower_rssi: Indicates RSSI of lower band
+ * @spectral_chain_ctl_rssi: RSSI for control channel, for all antennas
+ * @spectral_chain_ext_rssi: RSSI for extension channel, for all antennas
+ * @spectral_max_scale: Indicates scale factor
+ * @spectral_bwinfo: Indicates bandwidth info
+ * @spectral_tstamp: Indicates timestamp
+ * @spectral_max_index: Indicates the index of max magnitude
+ * @spectral_max_index_sec80: Indicates the index of max magnitude for secondary
+ * 80 segment
+ * @spectral_max_mag: Indicates the maximum magnitude
+ * @spectral_max_mag_sec80: Indicates the maximum magnitude for secondary 80
+ * segment
+ * @spectral_max_exp: Indicates the max exp
+ * @spectral_last_tstamp: Indicates the last time stamp
+ * @spectral_upper_max_index: Indicates the index of max mag in upper band
+ * @spectral_lower_max_index: Indicates the index of max mag in lower band
+ * @spectral_nb_upper: Not Used
+ * @spectral_nb_lower: Not Used
+ * @classifier_params: Indicates classifier parameters
+ * @bin_pwr_count: Indicates the number of FFT bins
+ * @lb_edge_extrabins: Number of extra bins on left band edge
+ * @rb_edge_extrabins: Number of extra bins on right band edge
+ * @bin_pwr_count_sec80: Indicates the number of FFT bins in secondary 80
+ * segment
+ * @bin_pwr: Contains FFT magnitudes
+ * @bin_pwr_sec80: Contains FFT magnitudes for the secondary 80
+ * segment
+ * @interf_list: List of interfernce sources
+ * @noise_floor: Indicates the current noise floor
+ * @noise_floor_sec80: Indicates the current noise floor for secondary 80
+ * segment
+ * @ch_width: Channel width 20/40/80/160 MHz
+ */
+typedef struct spectral_samp_data {
+ int16_t spectral_data_len;
+ int16_t spectral_data_len_sec80;
+ int16_t spectral_rssi;
+ int16_t spectral_rssi_sec80;
+ int8_t spectral_combined_rssi;
+ int8_t spectral_upper_rssi;
+ int8_t spectral_lower_rssi;
+ int8_t spectral_chain_ctl_rssi[MAX_SPECTRAL_CHAINS];
+ int8_t spectral_chain_ext_rssi[MAX_SPECTRAL_CHAINS];
+ u_int8_t spectral_max_scale;
+ int16_t spectral_bwinfo;
+ int32_t spectral_tstamp;
+ int16_t spectral_max_index;
+ int16_t spectral_max_index_sec80;
+ int16_t spectral_max_mag;
+ int16_t spectral_max_mag_sec80;
+ u_int8_t spectral_max_exp;
+ int32_t spectral_last_tstamp;
+ int16_t spectral_upper_max_index;
+ int16_t spectral_lower_max_index;
+ u_int8_t spectral_nb_upper;
+ u_int8_t spectral_nb_lower;
+ struct spectral_classifier_params classifier_params;
+ u_int16_t bin_pwr_count;
+ /* For 11ac chipsets prior to AR900B version 2.0, a max of 512 bins are
+ * delivered. However, there can be additional bins reported for
+ * AR900B version 2.0 and QCA9984 as described next:
+ *
+ * AR900B version 2.0: An additional tone is processed on the right
+ * hand side in order to facilitate detection of radar pulses out to
+ * the extreme band-edge of the channel frequency.
+ * Since the HW design processes four tones at a time,
+ * this requires one additional Dword to be added to the
+ * search FFT report.
+ *
+ * QCA9984: When spectral_scan_rpt_mode=2, i.e 2-dword summary +
+ * 1x-oversampled bins (in-band) per FFT,
+ * then 8 more bins (4 more on left side and 4 more on right side)
+ * are added.
+ */
+ u_int8_t lb_edge_extrabins;
+ u_int8_t rb_edge_extrabins;
+ u_int16_t bin_pwr_count_sec80;
+ u_int8_t bin_pwr[MAX_NUM_BINS];
+ u_int8_t bin_pwr_sec80[MAX_NUM_BINS];
+ struct INTERF_SRC_RSP interf_list;
+ int16_t noise_floor;
+ int16_t noise_floor_sec80;
+ u_int32_t ch_width;
+} __ATTRIB_PACKED SPECTRAL_SAMP_DATA;
+
+/**
+ * struct spectral_samp_msg - Spectral SAMP message
+ * @signature: Validates the SAMP message
+ * @freq: Operating frequency in MHz
+ * @vhtop_ch_freq_seg1: VHT Segment 1 centre frequency in MHz
+ * @vhtop_ch_freq_seg2: VHT Segment 2 centre frequency in MHz
+ * @freq_loading: How busy was the channel
+ * @dcs_enabled: Whether DCS is enabled
+ * @int_type: Interference type indicated by DCS
+ * @macaddr: Indicates the device interface
+ * @samp_data: SAMP Data
+ */
+typedef struct spectral_samp_msg {
+ u_int32_t signature;
+ u_int16_t freq;
+ u_int16_t vhtop_ch_freq_seg1;
+ u_int16_t vhtop_ch_freq_seg2;
+ u_int16_t freq_loading;
+ u_int16_t dcs_enabled;
+ DCS_INT_TYPE int_type;
+ u_int8_t macaddr[6];
+ SPECTRAL_SAMP_DATA samp_data;
+} __ATTRIB_PACKED SPECTRAL_SAMP_MSG;
+
+#ifdef WIN32
+#pragma pack(pop, spectral)
+#endif
+#ifdef __ATTRIB_PACKED
+#undef __ATTRIB_PACKED
+#endif
+
+#endif /* _WLAN_SPECTRAL_PUBLIC_STRUCTS_H_ */
+
diff --git a/spectral/dispatcher/inc/wlan_spectral_tgt_api.h b/spectral/dispatcher/inc/wlan_spectral_tgt_api.h
new file mode 100644
index 0000000..86f2972
--- /dev/null
+++ b/spectral/dispatcher/inc/wlan_spectral_tgt_api.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WLAN_SPECTRAL_TGT_API_H_
+#define _WLAN_SPECTRAL_TGT_API_H_
+
+#include <wlan_objmgr_cmn.h>
+#include <qdf_types.h>
+
+/**
+ * tgt_send_phydata() - Send Spectral PHY data over netlink
+ * @pdev: Pointer to pdev
+ * @sock: Netlink socket to use
+ * @nbuf: Network buffer containing PHY data to send
+ *
+ * Return: 0 on success, negative value on failure
+ */
+int tgt_send_phydata(struct wlan_objmgr_pdev *pdev,
+ struct sock *sock, qdf_nbuf_t nbuf);
+
+/**
+ * tgt_get_target_handle() - Get handle to target_if internal Spectral data
+ * @pdev: Pointer to pdev
+ *
+ * Return: Handle to target_if internal Spectral data on success, NULL on
+ * failure
+ */
+void *tgt_get_target_handle(struct wlan_objmgr_pdev *pdev);
+
+#endif /* _WLAN_SPECTRAL_TGT_API_H_*/
diff --git a/spectral/dispatcher/inc/wlan_spectral_ucfg_api.h b/spectral/dispatcher/inc/wlan_spectral_ucfg_api.h
new file mode 100644
index 0000000..0400494
--- /dev/null
+++ b/spectral/dispatcher/inc/wlan_spectral_ucfg_api.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WLAN_SPECTRAL_UCFG_API_H_
+#define _WLAN_SPECTRAL_UCFG_API_H_
+
+#include <wlan_objmgr_cmn.h>
+#include <wlan_spectral_public_structs.h>
+
+/* Spectral specific UCFG set operations */
+
+/**
+ * ucfg_spectral_control() - Carry out Spectral control get/set operations
+ * @pdev: Pointer to pdev
+ * @id: Spectral operation ID
+ * @indata: Pointer to input data
+ * @insize: Size of indata buffer
+ * @outdata: Pointer to buffer where the output should be stored
+ * @outsize: Size of outdata buffer
+ *
+ * Return: 0 on success, negative value on failure
+ */
+int ucfg_spectral_control(
+ struct wlan_objmgr_pdev *pdev,
+ u_int id,
+ void *indata,
+ u_int32_t insize,
+ void *outdata, u_int32_t *outsize);
+
+#endif /* _WLAN_SPECTRAL_UCFG_API_H_*/
diff --git a/spectral/dispatcher/inc/wlan_spectral_utils_api.h b/spectral/dispatcher/inc/wlan_spectral_utils_api.h
new file mode 100644
index 0000000..26825fa
--- /dev/null
+++ b/spectral/dispatcher/inc/wlan_spectral_utils_api.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2017 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WLAN_SPECTRAL_UTILS_API_H_
+#define _WLAN_SPECTRAL_UTILS_API_H_
+
+#include <wlan_objmgr_cmn.h>
+#include <wlan_lmac_if_def.h>
+
+/**
+ * wlan_spectral_init(): API to init spectral component
+ *
+ * This API is invoked from dispatcher init during all component init.
+ * This API will register all required handlers for pdev and peer object
+ * create/delete notification.
+ *
+ * Return: SUCCESS,
+ * Failure
+ */
+QDF_STATUS wlan_spectral_init(void);
+
+/**
+ * wlan_spectral_deinit(): API to deinit spectral component
+ *
+ * This API is invoked from dispatcher deinit during all component deinit.
+ * This API will unregister all registered handlers for pdev and peer object
+ * create/delete notification.
+ *
+ * Return: SUCCESS,
+ * Failure
+ */
+QDF_STATUS wlan_spectral_deinit(void);
+
+/**
+ * wlan_lmac_if_sptrl_register_rx_ops(): Register lmac interface Rx operations
+ * @rx_ops: Pointer to lmac interface Rx operations structure
+ *
+ * Return: None
+ */
+void wlan_lmac_if_sptrl_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops);
+
+#endif /* _WLAN_SPECTRAL_UTILS_API_H_*/
diff --git a/spectral/dispatcher/src/wlan_spectral_tgt_api.c b/spectral/dispatcher/src/wlan_spectral_tgt_api.c
new file mode 100644
index 0000000..a3fa5bc
--- /dev/null
+++ b/spectral/dispatcher/src/wlan_spectral_tgt_api.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2011,2017 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 <wlan_spectral_tgt_api.h>
+#include "../../core/spectral_cmn_api_i.h"
+
+int tgt_send_phydata(struct wlan_objmgr_pdev *pdev,
+ struct sock *sock, qdf_nbuf_t nbuf)
+{
+ return netlink_broadcast(sock, nbuf, 0, 1, GFP_ATOMIC);
+}
+
+void *tgt_get_target_handle(struct wlan_objmgr_pdev *pdev)
+{
+ struct pdev_spectral *ps;
+
+ if (!pdev) {
+ spectral_err("PDEV is NULL!\n");
+ return NULL;
+ }
+ ps = wlan_objmgr_pdev_get_comp_private_obj(
+ pdev,
+ WLAN_UMAC_COMP_SPECTRAL);
+ if (!ps) {
+ spectral_err("PDEV SPECTRAL object is NULL!\n");
+ return NULL;
+ }
+ return ps->psptrl_target_handle;
+}
diff --git a/spectral/dispatcher/src/wlan_spectral_ucfg_api.c b/spectral/dispatcher/src/wlan_spectral_ucfg_api.c
new file mode 100644
index 0000000..b063f9d
--- /dev/null
+++ b/spectral/dispatcher/src/wlan_spectral_ucfg_api.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 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 <wlan_spectral_ucfg_api.h>
+#include "../../core/spectral_cmn_api_i.h"
+#include <wlan_spectral_utils_api.h>
+
+int ucfg_spectral_control(
+ struct wlan_objmgr_pdev *pdev,
+ u_int id,
+ void *indata,
+ u_int32_t insize,
+ void *outdata, u_int32_t *outsize)
+{
+ struct spectral_context *sc;
+
+ if (!pdev) {
+ spectral_err("PDEV is NULL!\n");
+ return -EPERM;
+ }
+ sc = spectral_get_spectral_ctx_from_pdev(pdev);
+ if (!sc) {
+ spectral_err("spectral context is NULL!\n");
+ return -EPERM;
+ }
+ return sc->sptrlc_spectral_control(
+ pdev,
+ id,
+ indata,
+ insize,
+ outdata,
+ outsize);
+}
+EXPORT_SYMBOL(ucfg_spectral_control);
diff --git a/spectral/dispatcher/src/wlan_spectral_utils_api.c b/spectral/dispatcher/src/wlan_spectral_utils_api.c
new file mode 100644
index 0000000..d65a9cd
--- /dev/null
+++ b/spectral/dispatcher/src/wlan_spectral_utils_api.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2017 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 <wlan_spectral_utils_api.h>
+#include <qdf_module.h>
+#include "../../core/spectral_cmn_api_i.h"
+#include <wlan_spectral_tgt_api.h>
+
+QDF_STATUS wlan_spectral_init(void)
+{
+ if (wlan_objmgr_register_psoc_create_handler(
+ WLAN_UMAC_COMP_SPECTRAL,
+ wlan_spectral_psoc_obj_create_handler,
+ NULL) != QDF_STATUS_SUCCESS) {
+ return QDF_STATUS_E_FAILURE;
+ }
+ if (wlan_objmgr_register_psoc_destroy_handler(
+ WLAN_UMAC_COMP_SPECTRAL,
+ wlan_spectral_psoc_obj_destroy_handler,
+ NULL) != QDF_STATUS_SUCCESS) {
+ return QDF_STATUS_E_FAILURE;
+ }
+ if (wlan_objmgr_register_pdev_create_handler(
+ WLAN_UMAC_COMP_SPECTRAL,
+ wlan_spectral_pdev_obj_create_handler,
+ NULL) != QDF_STATUS_SUCCESS) {
+ return QDF_STATUS_E_FAILURE;
+ }
+ if (wlan_objmgr_register_pdev_destroy_handler(
+ WLAN_UMAC_COMP_SPECTRAL,
+ wlan_spectral_pdev_obj_destroy_handler,
+ NULL) != QDF_STATUS_SUCCESS) {
+ return QDF_STATUS_E_FAILURE;
+ }
+
+ return QDF_STATUS_SUCCESS;
+}
+
+QDF_STATUS wlan_spectral_deinit(void)
+{
+ if (wlan_objmgr_unregister_psoc_create_handler(
+ WLAN_UMAC_COMP_SPECTRAL,
+ wlan_spectral_psoc_obj_create_handler,
+ NULL) != QDF_STATUS_SUCCESS) {
+ return QDF_STATUS_E_FAILURE;
+ }
+ if (wlan_objmgr_unregister_psoc_destroy_handler(
+ WLAN_UMAC_COMP_SPECTRAL,
+ wlan_spectral_psoc_obj_destroy_handler,
+ NULL) != QDF_STATUS_SUCCESS) {
+ return QDF_STATUS_E_FAILURE;
+ }
+ if (wlan_objmgr_unregister_pdev_create_handler(
+ WLAN_UMAC_COMP_SPECTRAL,
+ wlan_spectral_pdev_obj_create_handler,
+ NULL) != QDF_STATUS_SUCCESS) {
+ return QDF_STATUS_E_FAILURE;
+ }
+ if (wlan_objmgr_unregister_pdev_destroy_handler(
+ WLAN_UMAC_COMP_SPECTRAL,
+ wlan_spectral_pdev_obj_destroy_handler,
+ NULL) != QDF_STATUS_SUCCESS) {
+ return QDF_STATUS_E_FAILURE;
+ }
+ return QDF_STATUS_SUCCESS;
+}
+
+void wlan_lmac_if_sptrl_register_rx_ops(struct wlan_lmac_if_rx_ops *rx_ops)
+{
+ struct wlan_lmac_if_sptrl_rx_ops *sptrl_rx_ops = &rx_ops->sptrl_rx_ops;
+
+ /* Spectral rx ops */
+ sptrl_rx_ops->sptrlro_send_phydata = tgt_send_phydata;
+ sptrl_rx_ops->sptrlro_get_target_handle = tgt_get_target_handle;
+}
diff --git a/target_if/spectral/target_if_spectral.c b/target_if/spectral/target_if_spectral.c
new file mode 100644
index 0000000..5c02c50
--- /dev/null
+++ b/target_if/spectral/target_if_spectral.c
@@ -0,0 +1,2509 @@
+/*
+ * Copyright (c) 2011,2017 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 <wlan_tgt_def_config.h>
+#include <hif.h>
+#include <hif_hw_version.h>
+#include <wmi_unified_api.h>
+#include <target_if_spectral.h>
+#include <wlan_lmac_if_def.h>
+#include <wlan_osif_priv.h>
+#include <reg_services_public_struct.h>
+#include <wlan_mlme_dispatcher.h>
+#include <target_if_spectral_sim.h>
+
+/**
+ * @spectral_ops - Spectral function table, holds the Spectral functions that
+ * depend on whether the architecture is Direct Attach or Offload. This is used
+ * to populate the actual Spectral function table present in the Spectral
+ * module.
+ */
+struct target_if_spectral_ops spectral_ops;
+
+/**
+ * target_if_spectral_get_vdev() - Get pointer to vdev to be used for Spectral
+ * operations
+ * @spectral: Pointer to Spectral target_if internal private data
+ *
+ * Spectral operates on pdev. However, in order to retrieve some WLAN
+ * properties, a vdev is required. To facilitate this, the function returns the
+ * first vdev in our pdev. The caller should release the reference to the vdev
+ * once it is done using it.
+ * TODO: If the framework later provides an API to obtain the first active
+ * vdev, then it would be preferable to use this API.
+ *
+ * Return: Pointer to vdev on success, NULL on failure
+ */
+struct wlan_objmgr_vdev *
+target_if_spectral_get_vdev(struct target_if_spectral *spectral)
+{
+ struct wlan_objmgr_pdev *pdev = NULL;
+ struct wlan_objmgr_vdev *vdev = NULL;
+
+ qdf_assert_always(spectral);
+ pdev = spectral->pdev_obj;
+ qdf_assert_always(pdev);
+
+ if (wlan_objmgr_pdev_try_get_ref(pdev, WLAN_SPECTRAL_ID) !=
+ QDF_STATUS_SUCCESS) {
+ qdf_print("%s: Unable to get pdev reference.\n", __func__);
+ return NULL;
+ }
+
+ vdev = wlan_objmgr_get_vdev_by_id_from_pdev(pdev, 0, WLAN_SPECTRAL_ID);
+
+ wlan_objmgr_pdev_release_ref(pdev, WLAN_SPECTRAL_ID);
+
+ if (!vdev) {
+ qdf_print("%s: Unable to get first vdev of pdev.\n", __func__);
+ return NULL;
+ }
+
+ return vdev;
+}
+
+/**
+ * wmi_send_vdev_spectral_configure_cmd() - Send WMI command to configure
+ * Spectral parameters
+ * @spectral: Pointer to Spectral target_if internal private data
+ * @param: Pointer to spectral_config giving the Spectral configuration
+ *
+ * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
+ */
+int wmi_send_vdev_spectral_configure_cmd(struct target_if_spectral *spectral,
+ struct spectral_config *param)
+{
+ struct ol_ath_softc_net80211 *scn = NULL;
+ struct pdev_osif_priv *osif_priv = NULL;
+ struct vdev_spectral_configure_params sparam;
+ struct wlan_objmgr_pdev *pdev = NULL;
+ struct wlan_objmgr_vdev *vdev = NULL;
+
+ qdf_assert_always(spectral && param);
+
+ pdev = spectral->pdev_obj;
+
+ qdf_assert_always(pdev);
+
+ osif_priv = wlan_pdev_get_ospriv(pdev);
+ scn = (struct ol_ath_softc_net80211 *)osif_priv->legacy_osif_priv;
+
+ vdev = target_if_spectral_get_vdev(spectral);
+ if (!vdev)
+ return QDF_STATUS_E_NOENT;
+
+ qdf_mem_set(&sparam, sizeof(sparam), 0);
+
+ sparam.vdev_id = wlan_vdev_get_id(vdev);
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
+
+ sparam.count = param->ss_count;
+ sparam.period = param->ss_period;
+ sparam.spectral_pri = param->ss_spectral_pri;
+ sparam.fft_size = param->ss_fft_size;
+ sparam.gc_enable = param->ss_gc_ena;
+ sparam.restart_enable = param->ss_restart_ena;
+ sparam.noise_floor_ref = param->ss_noise_floor_ref;
+ sparam.init_delay = param->ss_init_delay;
+ sparam.nb_tone_thr = param->ss_nb_tone_thr;
+ sparam.str_bin_thr = param->ss_str_bin_thr;
+ sparam.wb_rpt_mode = param->ss_wb_rpt_mode;
+ sparam.rssi_rpt_mode = param->ss_rssi_rpt_mode;
+ sparam.rssi_thr = param->ss_rssi_thr;
+ sparam.pwr_format = param->ss_pwr_format;
+ sparam.rpt_mode = param->ss_rpt_mode;
+ sparam.bin_scale = param->ss_bin_scale;
+ sparam.dBm_adj = param->ss_dBm_adj;
+ sparam.chn_mask = param->ss_chn_mask;
+
+ return scn->wmi_spectral_configure_cmd_send(scn->wmi_handle, &sparam);
+}
+
+/**
+ * wmi_send_vdev_spectral_enable_cmd() - Send WMI command to enable/disable
+ * Spectral
+ * @spectral: Pointer to Spectral target_if internal private data
+ * @is_spectral_active_valid: Flag to indicate if spectral activate (trigger) is
+ * valid
+ * @is_spectral_active: Value of spectral activate
+ * @is_spectral_enabled_valid: Flag to indicate if spectral enable is valid
+ * @is_spectral_enabled: Value of spectral enable
+ *
+ * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
+ */
+int wmi_send_vdev_spectral_enable_cmd(struct target_if_spectral *spectral,
+ u_int8_t is_spectral_active_valid,
+ u_int8_t is_spectral_active,
+ u_int8_t is_spectral_enabled_valid,
+ u_int8_t is_spectral_enabled)
+{
+ struct vdev_spectral_enable_params param;
+ struct ol_ath_softc_net80211 *scn = NULL;
+ struct pdev_osif_priv *osif_priv = NULL;
+ struct wlan_objmgr_pdev *pdev = NULL;
+ struct wlan_objmgr_vdev *vdev = NULL;
+
+ qdf_assert_always(spectral);
+
+ pdev = spectral->pdev_obj;
+
+ qdf_assert_always(pdev);
+
+ osif_priv = wlan_pdev_get_ospriv(pdev);
+ scn = (struct ol_ath_softc_net80211 *)osif_priv->legacy_osif_priv;
+
+ vdev = target_if_spectral_get_vdev(spectral);
+ if (!vdev)
+ return QDF_STATUS_E_NOENT;
+
+ qdf_mem_set(¶m, sizeof(param), 0);
+
+ param.vdev_id = wlan_vdev_get_id(vdev);
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
+
+ param.active_valid = is_spectral_active_valid;
+ param.enabled_valid = is_spectral_enabled_valid;
+ param.active = is_spectral_active;
+ param.enabled = is_spectral_enabled;
+
+ return scn->wmi_spectral_enable_cmd_send(scn->wmi_handle, ¶m);
+}
+
+/**
+ * target_if_spectral_info_init_defaults() - Helper function to load defaults
+ * for Spectral information (parameters and state) into cache.
+ * @spectral: Pointer to Spectral target_if internal private data
+ *
+ * It is assumed that the caller has obtained the requisite lock if applicable.
+ * Note that this is currently treated as a temporary function. Ideally, we
+ * would like to get defaults from the firmware.
+ *
+ * Return: QDF_STATUS_SUCCESS on success, negative error code on failure
+ */
+int target_if_spectral_info_init_defaults(struct target_if_spectral *spectral)
+{
+ struct target_if_spectral_param_state_info *info = &spectral->ol_info;
+ struct wlan_objmgr_vdev *vdev = NULL;
+
+ /* State */
+ info->osps_cache.osc_spectral_active =
+ SPECTRAL_SCAN_ACTIVE_DEFAULT;
+
+ info->osps_cache.osc_spectral_enabled =
+ SPECTRAL_SCAN_ENABLE_DEFAULT;
+
+ /* Parameters */
+ info->osps_cache.osc_params.ss_count =
+ SPECTRAL_SCAN_COUNT_DEFAULT;
+
+ info->osps_cache.osc_params.ss_period =
+ SPECTRAL_SCAN_PERIOD_DEFAULT;
+
+ info->osps_cache.osc_params.ss_spectral_pri =
+ SPECTRAL_SCAN_PRIORITY_DEFAULT;
+
+ info->osps_cache.osc_params.ss_fft_size =
+ SPECTRAL_SCAN_FFT_SIZE_DEFAULT;
+
+ info->osps_cache.osc_params.ss_gc_ena =
+ SPECTRAL_SCAN_GC_ENA_DEFAULT;
+
+ info->osps_cache.osc_params.ss_restart_ena =
+ SPECTRAL_SCAN_RESTART_ENA_DEFAULT;
+
+ info->osps_cache.osc_params.ss_noise_floor_ref =
+ SPECTRAL_SCAN_NOISE_FLOOR_REF_DEFAULT;
+
+ info->osps_cache.osc_params.ss_init_delay =
+ SPECTRAL_SCAN_INIT_DELAY_DEFAULT;
+
+ info->osps_cache.osc_params.ss_nb_tone_thr =
+ SPECTRAL_SCAN_NB_TONE_THR_DEFAULT;
+
+ info->osps_cache.osc_params.ss_str_bin_thr =
+ SPECTRAL_SCAN_STR_BIN_THR_DEFAULT;
+
+ info->osps_cache.osc_params.ss_wb_rpt_mode =
+ SPECTRAL_SCAN_WB_RPT_MODE_DEFAULT;
+
+ info->osps_cache.osc_params.ss_rssi_rpt_mode =
+ SPECTRAL_SCAN_RSSI_RPT_MODE_DEFAULT;
+
+ info->osps_cache.osc_params.ss_rssi_thr =
+ SPECTRAL_SCAN_RSSI_THR_DEFAULT;
+
+ info->osps_cache.osc_params.ss_pwr_format =
+ SPECTRAL_SCAN_PWR_FORMAT_DEFAULT;
+
+ info->osps_cache.osc_params.ss_rpt_mode =
+ SPECTRAL_SCAN_RPT_MODE_DEFAULT;
+
+ info->osps_cache.osc_params.ss_bin_scale =
+ SPECTRAL_SCAN_BIN_SCALE_DEFAULT;
+
+ info->osps_cache.osc_params.ss_dBm_adj =
+ SPECTRAL_SCAN_DBM_ADJ_DEFAULT;
+
+ vdev = target_if_spectral_get_vdev(spectral);
+ if (!vdev)
+ return QDF_STATUS_E_NOENT;
+
+ info->osps_cache.osc_params.ss_chn_mask =
+ wlan_vdev_mlme_get_rxchainmask(vdev);
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
+
+ /* The cache is now valid */
+ info->osps_cache.osc_is_valid = 1;
+
+ return QDF_STATUS_SUCCESS;
+}
+
+/**
+ * ol_spectral_info_read() - Read Spectral parameters or the desired state
+ * information from the cache.
+ * @spectral: Pointer to Spectral target_if internal private data
+ * @specifier: ol_spectral_info_spec enumeration specifying which information is
+ * required
+ * @output: Void output pointer into which the information will be read
+ * @output_len: size of object pointed to by output pointer
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int ol_spectral_info_read(struct target_if_spectral *spectral,
+ enum ol_spectral_info_spec specifier,
+ void *output,
+ int output_len)
+{
+ /* Note: This function is designed to be able to accommodate
+ * WMI reads for defaults, non-cacheable information, etc
+ * if required.
+ */
+ struct target_if_spectral_param_state_info *info = &spectral->ol_info;
+ int is_cacheable = 0;
+ int init_def_retval = 0;
+
+ if (!output)
+ return -EINVAL;
+
+ switch (specifier) {
+ case OL_SPECTRAL_INFO_SPEC_ACTIVE:
+ if (output_len !=
+ sizeof(info->osps_cache.osc_spectral_active))
+ return -EINVAL;
+ is_cacheable = 1;
+ break;
+
+ case OL_SPECTRAL_INFO_SPEC_ENABLED:
+ if (output_len !=
+ sizeof(info->osps_cache.osc_spectral_enabled))
+ return -EINVAL;
+ is_cacheable = 1;
+ break;
+
+ case OL_SPECTRAL_INFO_SPEC_PARAMS:
+ if (output_len != sizeof(info->osps_cache.osc_params))
+ return -EINVAL;
+ is_cacheable = 1;
+ break;
+
+ default:
+ qdf_print("%s: Unknown ol_spectral_info_spec specifier\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ qdf_spin_lock(&info->osps_lock);
+
+ if (is_cacheable) {
+ if (info->osps_cache.osc_is_valid) {
+ switch (specifier) {
+ case OL_SPECTRAL_INFO_SPEC_ACTIVE:
+ qdf_mem_copy(
+ output,
+ &info->osps_cache.osc_spectral_active,
+ sizeof(info->osps_cache.osc_spectral_active));
+#ifdef OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS
+ qdf_print("%s: OL_SPECTRAL_INFO_SPEC_ACTIVE. "
+ "Returning val=%u\n",
+ __func__,
+ *((unsigned char *)output));
+#endif /* OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS */
+ break;
+
+ case OL_SPECTRAL_INFO_SPEC_ENABLED:
+ qdf_mem_copy(
+ output,
+ &info->osps_cache.osc_spectral_enabled,
+ sizeof(info->osps_cache.osc_spectral_enabled));
+#ifdef OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS
+ qdf_print("%s: OL_SPECTRAL_INFO_SPEC_ENABLED. "
+ "Returning val=%u\n",
+ __func__,
+ *((unsigned char *)output));
+#endif /* OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS */
+
+ break;
+
+ case OL_SPECTRAL_INFO_SPEC_PARAMS:
+ qdf_mem_copy(
+ output,
+ &info->osps_cache.osc_params,
+ sizeof(info->osps_cache.osc_params));
+#ifdef OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS
+ {
+ struct spectral_config *pparam =
+ (struct spectral_config *)output;
+
+ qdf_print("%s: OL_SPECTRAL_INFO_SPEC_PARAMS. "
+ "Returning following params:\n"
+ "ss_count = %u\n"
+ "ss_period = %u\n"
+ "ss_spectral_pri = %u\n"
+ "ss_fft_size = %u\n"
+ "ss_gc_ena = %u\n"
+ "ss_restart_ena = %u\n"
+ "ss_noise_floor_ref = %d\n"
+ "ss_init_delay = %u\n"
+ "ss_nb_tone_thr = %u\n"
+ "ss_str_bin_thr = %u\n"
+ "ss_wb_rpt_mode = %u\n"
+ "ss_rssi_rpt_mode = %u\n"
+ "ss_rssi_thr = %d\n"
+ "ss_pwr_format = %u\n"
+ "ss_rpt_mode = %u\n"
+ "ss_bin_scale = %u\n"
+ "ss_dBm_adj = %u\n"
+ "ss_chn_mask = %u\n\n",
+ __func__,
+ pparam->ss_count,
+ pparam->ss_period,
+ pparam->ss_spectral_pri,
+ pparam->ss_fft_size,
+ pparam->ss_gc_ena,
+ pparam->ss_restart_ena,
+ (int8_t)pparam->ss_noise_floor_ref,
+ pparam->ss_init_delay,
+ pparam->ss_nb_tone_thr,
+ pparam->ss_str_bin_thr,
+ pparam->ss_wb_rpt_mode,
+ pparam->ss_rssi_rpt_mode,
+ (int8_t)pparam->ss_rssi_thr,
+ pparam->ss_pwr_format,
+ pparam->ss_rpt_mode,
+ pparam->ss_bin_scale,
+ pparam->ss_dBm_adj,
+ pparam->ss_chn_mask);
+ }
+#endif /* OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS */
+ break;
+
+ default:
+ /* We can't reach this point */
+ break;
+ }
+ qdf_spin_unlock(&info->osps_lock);
+ return 0;
+ }
+ }
+
+ /* Cache is invalid */
+
+ /* If WMI Reads are implemented to fetch defaults/non-cacheable info,
+ * then the below implementation will change
+ */
+ init_def_retval = target_if_spectral_info_init_defaults(spectral);
+ if (init_def_retval != QDF_STATUS_SUCCESS) {
+ if (init_def_retval == QDF_STATUS_E_NOENT)
+ return -ENOENT;
+ else
+ return -EINVAL;
+ }
+ /* target_if_spectral_info_init_defaults() has set cache to valid */
+
+ switch (specifier) {
+ case OL_SPECTRAL_INFO_SPEC_ACTIVE:
+ qdf_mem_copy(output,
+ &info->osps_cache.osc_spectral_active,
+ sizeof(info->osps_cache.osc_spectral_active));
+#ifdef OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS
+ qdf_print("%s: OL_SPECTRAL_INFO_SPEC_ACTIVE on "
+ "initial cache validation\n"
+ "Returning val=%u\n",
+ __func__,
+ *((unsigned char *)output));
+#endif /* OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS */
+ break;
+
+ case OL_SPECTRAL_INFO_SPEC_ENABLED:
+ qdf_mem_copy(output,
+ &info->osps_cache.osc_spectral_enabled,
+ sizeof(info->osps_cache.osc_spectral_enabled));
+#ifdef OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS
+ qdf_print("%s: OL_SPECTRAL_INFO_SPEC_ENABLED on "
+ "initial cache validation\n"
+ "Returning val=%u\n",
+ __func__,
+ *((unsigned char *)output));
+#endif /* OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS */
+ break;
+
+ case OL_SPECTRAL_INFO_SPEC_PARAMS:
+ qdf_mem_copy(output,
+ &info->osps_cache.osc_params,
+ sizeof(info->osps_cache.osc_params));
+#ifdef OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS
+ {
+ struct spectral_config *pparam =
+ (struct spectral_config *)output;
+
+ qdf_print("%s: OL_SPECTRAL_INFO_SPEC_PARAMS on "
+ "initial cache validation\n"
+ "Returning following params:\n"
+ "ss_count = %u\n"
+ "ss_period = %u\n"
+ "ss_spectral_pri = %u\n"
+ "ss_fft_size = %u\n"
+ "ss_gc_ena = %u\n"
+ "ss_restart_ena = %u\n"
+ "ss_noise_floor_ref = %d\n"
+ "ss_init_delay = %u\n"
+ "ss_nb_tone_thr = %u\n"
+ "ss_str_bin_thr = %u\n"
+ "ss_wb_rpt_mode = %u\n"
+ "ss_rssi_rpt_mode = %u\n"
+ "ss_rssi_thr = %d\n"
+ "ss_pwr_format = %u\n"
+ "ss_rpt_mode = %u\n"
+ "ss_bin_scale = %u\n"
+ "ss_dBm_adj = %u\n"
+ "ss_chn_mask = %u\n\n",
+ __func__,
+ pparam->ss_count,
+ pparam->ss_period,
+ pparam->ss_spectral_pri,
+ pparam->ss_fft_size,
+ pparam->ss_gc_ena,
+ pparam->ss_restart_ena,
+ (int8_t)pparam->ss_noise_floor_ref,
+ pparam->ss_init_delay,
+ pparam->ss_nb_tone_thr,
+ pparam->ss_str_bin_thr,
+ pparam->ss_wb_rpt_mode,
+ pparam->ss_rssi_rpt_mode,
+ (int8_t)pparam->ss_rssi_thr,
+ pparam->ss_pwr_format,
+ pparam->ss_rpt_mode,
+ pparam->ss_bin_scale,
+ pparam->ss_dBm_adj,
+ pparam->ss_chn_mask);
+ }
+#endif /* OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS */
+
+ break;
+
+ default:
+ /* We can't reach this point */
+ break;
+ }
+
+ qdf_spin_unlock(&info->osps_lock);
+
+ return 0;
+}
+
+/**
+ * ol_spectral_info_write() - Write Spectral parameters or the desired state
+ * information to the firmware, and update cache
+ * @spectral: Pointer to Spectral target_if internal private data
+ * @specifier: ol_spectral_info_spec enumeration specifying which information is
+ * involved
+ * @input: void input pointer containing the information to be written
+ * @input_len: size of object pointed to by input pointer
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int ol_spectral_info_write(struct target_if_spectral *spectral,
+ enum ol_spectral_info_spec specifier,
+ void *input,
+ int input_len)
+{
+ struct target_if_spectral_param_state_info *info = &spectral->ol_info;
+ int ret;
+ u_int8_t *pval = NULL;
+ struct spectral_config *param = NULL;
+
+ if (!input)
+ return -EINVAL;
+
+ switch (specifier) {
+ case OL_SPECTRAL_INFO_SPEC_ACTIVE:
+ if (input_len !=
+ sizeof(info->osps_cache.osc_spectral_active))
+ return -EINVAL;
+
+ pval = (u_int8_t *)input;
+
+ qdf_spin_lock(&info->osps_lock);
+ ret = wmi_send_vdev_spectral_enable_cmd(
+ spectral,
+ 1,
+ *pval,
+ 0,
+ 0);
+
+#ifdef OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS
+ qdf_print("%s: OL_SPECTRAL_INFO_SPEC_ACTIVE with "
+ "val=%u status=%d\n",
+ __func__,
+ *pval,
+ ret);
+#endif /* OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS */
+
+ if (ret < 0) {
+ qdf_print(
+ "%s: wmi_send_vdev_spectral_enable_cmd "
+ "failed with error=%d\n",
+ __func__,
+ ret);
+ qdf_spin_unlock(&info->osps_lock);
+ return ret;
+ }
+
+ info->osps_cache.osc_spectral_active = *pval;
+ qdf_spin_unlock(&info->osps_lock);
+ break;
+
+ case OL_SPECTRAL_INFO_SPEC_ENABLED:
+ if (input_len !=
+ sizeof(info->osps_cache.osc_spectral_enabled))
+ return -EINVAL;
+
+ pval = (u_int8_t *)input;
+
+ qdf_spin_lock(&info->osps_lock);
+ ret = wmi_send_vdev_spectral_enable_cmd(
+ spectral,
+ 0,
+ 0,
+ 1,
+ *pval);
+
+#ifdef OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS
+ qdf_print("%s: OL_SPECTRAL_INFO_SPEC_ENABLED with "
+ "val=%u status=%d\n",
+ __func__,
+ *pval,
+ ret);
+#endif /* OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS */
+
+ if (ret < 0) {
+ qdf_print(
+ "%s: wmi_send_vdev_spectral_enable_cmd "
+ "failed with error=%d\n",
+ __func__,
+ ret);
+ qdf_spin_unlock(&info->osps_lock);
+ return ret;
+ }
+
+ info->osps_cache.osc_spectral_enabled = *pval;
+ qdf_spin_unlock(&info->osps_lock);
+ break;
+
+ case OL_SPECTRAL_INFO_SPEC_PARAMS:
+ if (input_len != sizeof(info->osps_cache.osc_params))
+ return -EINVAL;
+
+ param = (struct spectral_config *)input;
+
+ qdf_spin_lock(&info->osps_lock);
+ ret = wmi_send_vdev_spectral_configure_cmd(
+ spectral,
+ param);
+
+#ifdef OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS
+ qdf_print("%s: OL_SPECTRAL_INFO_SPEC_PARAMS. "
+ "Params:\n"
+ "ss_count = %u\n"
+ "ss_period = %u\n"
+ "ss_spectral_pri = %u\n"
+ "ss_fft_size = %u\n"
+ "ss_gc_ena = %u\n"
+ "ss_restart_ena = %u\n"
+ "ss_noise_floor_ref = %d\n"
+ "ss_init_delay = %u\n"
+ "ss_nb_tone_thr = %u\n"
+ "ss_str_bin_thr = %u\n"
+ "ss_wb_rpt_mode = %u\n"
+ "ss_rssi_rpt_mode = %u\n"
+ "ss_rssi_thr = %d\n"
+ "ss_pwr_format = %u\n"
+ "ss_rpt_mode = %u\n"
+ "ss_bin_scale = %u\n"
+ "ss_dBm_adj = %u\n"
+ "ss_chn_mask = %u\n"
+ "status = %d\n\n",
+ __func__,
+ param->ss_count,
+ param->ss_period,
+ param->ss_spectral_pri,
+ param->ss_fft_size,
+ param->ss_gc_ena,
+ param->ss_restart_ena,
+ (int8_t)param->ss_noise_floor_ref,
+ param->ss_init_delay,
+ param->ss_nb_tone_thr,
+ param->ss_str_bin_thr,
+ param->ss_wb_rpt_mode,
+ param->ss_rssi_rpt_mode,
+ (int8_t)param->ss_rssi_thr,
+ param->ss_pwr_format,
+ param->ss_rpt_mode,
+ param->ss_bin_scale,
+ param->ss_dBm_adj,
+ param->ss_chn_mask,
+ ret);
+#endif /* OL_SPECTRAL_DEBUG_CONFIG_INTERACTIONS */
+
+ if (ret < 0) {
+ qdf_print(
+ "%s: wmi_send_vdev_spectral_configure_cmd "
+ "failed with error=%d\n",
+ __func__,
+ ret);
+ qdf_spin_unlock(&info->osps_lock);
+ return ret;
+ }
+
+ qdf_mem_copy(&info->osps_cache.osc_params,
+ param,
+ sizeof(info->osps_cache.osc_params));
+ qdf_spin_unlock(&info->osps_lock);
+ break;
+
+ default:
+ qdf_print("%s: Unknown OL_SPECTRAL_INFO_SPEC_T "
+ "specifier\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * target_if_spectral_get_tsf64() - Get the last TSF received in WMI buffer
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * Return: TSF value
+ */
+static u_int64_t target_if_spectral_get_tsf64(void *arg)
+{
+ struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
+
+ return spectral->tsf64;
+}
+
+/**
+ * target_if_spectral_get_capability() - Get whether a given Spectral hardware
+ * capability is available
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ * @type: Spectral hardware capability type
+ *
+ * Return: True if the capability is available, false if the capability is not
+ * available
+ */
+u_int32_t target_if_spectral_get_capability(
+ void *arg,
+ SPECTRAL_CAPABILITY_TYPE type)
+{
+ int status = STATUS_FAIL;
+
+ switch (type) {
+ case SPECTRAL_CAP_PHYDIAG:
+ case SPECTRAL_CAP_RADAR:
+ case SPECTRAL_CAP_SPECTRAL_SCAN:
+ case SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN:
+ status = STATUS_PASS;
+ break;
+ default:
+ status = STATUS_FAIL;
+ }
+ return status;
+}
+
+/**
+ * target_if_spectral_set_rxfilter() - Set the RX Filter before Spectral start
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ * @rxfilter: Rx filter to be used
+ *
+ * Note: This is only a placeholder function. It is not currently required since
+ * FW should be taking care of setting the required filters.
+ *
+ * Return: 0
+ */
+u_int32_t target_if_spectral_set_rxfilter(void *arg, int rxfilter)
+{
+ /* Will not be required since enabling of spectral in firmware
+ * will take care of this
+ */
+ return 0;
+}
+
+/**
+ * target_if_spectral_get_rxfilter() - Get the current RX Filter settings
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * Note: This is only a placeholder function. It is not currently required since
+ * FW should be taking care of setting the required filters.
+ *
+ * Return: 0
+ */
+u_int32_t target_if_spectral_get_rxfilter(void *arg)
+{
+ /* Will not be required since enabling of spectral in firmware
+ * will take care of this
+ */
+ return 0;
+}
+
+/**
+ * tgt_if_is_spectral_active() - Get whether Spectral is active
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * Return: True if Spectral is active, false if Spectral is not active
+ */
+u_int32_t tgt_if_is_spectral_active(void *arg)
+{
+ struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
+ u_int8_t val = 0;
+ int ret;
+
+ ret = ol_spectral_info_read(spectral,
+ OL_SPECTRAL_INFO_SPEC_ACTIVE,
+ &val,
+ sizeof(val));
+
+ if (ret != 0) {
+ /* Could not determine if Spectral is active.
+ * Return false as a safe value.
+ * XXX: Consider changing the function prototype
+ * to be able to indicate failure to fetch value.
+ */
+ return 0;
+ }
+
+ return val;
+}
+
+/**
+ * tgt_if_is_spectral_enabled() - Get whether Spectral is enabled
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * Return: True if Spectral is enabled, false if Spectral is not enabled
+ */
+u_int32_t tgt_if_is_spectral_enabled(void *arg)
+{
+ struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
+ u_int8_t val = 0;
+ int ret;
+
+ ret = ol_spectral_info_read(spectral,
+ OL_SPECTRAL_INFO_SPEC_ENABLED,
+ &val,
+ sizeof(val));
+
+ if (ret != 0) {
+ /* Could not determine if Spectral is enabled.
+ * Return false as a safe value.
+ * XXX: Consider changing the function prototype
+ * to be able to indicate failure to fetch value.
+ */
+ return 0;
+ }
+
+ return val;
+}
+
+/**
+ * tgt_if_start_spectral_scan() - Start Spectral scan
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * Return: 1 on success, 0 on failure
+ */
+u_int32_t tgt_if_start_spectral_scan(void *arg)
+{
+ struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
+ u_int8_t val = 1;
+ u_int8_t enabled = 0;
+ int ret;
+
+ ret = ol_spectral_info_read(spectral,
+ OL_SPECTRAL_INFO_SPEC_ENABLED,
+ &enabled,
+ sizeof(enabled));
+
+ if (ret != 0) {
+ /* Could not determine if Spectral is enabled. Assume we need
+ * to enable it
+ */
+ enabled = 0;
+ }
+
+ if (!enabled) {
+ ret = ol_spectral_info_write(spectral,
+ OL_SPECTRAL_INFO_SPEC_ENABLED,
+ &val,
+ sizeof(val));
+
+ if (ret != 0)
+ return 0;
+ }
+
+ ret = ol_spectral_info_write(spectral,
+ OL_SPECTRAL_INFO_SPEC_ACTIVE,
+ &val,
+ sizeof(val));
+
+ if (ret != 0)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * tgt_if_stop_spectral_scan() - Stop Spectral scan
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * Return: 1 on success, 0 on failure
+ */
+u_int32_t tgt_if_stop_spectral_scan(void *arg)
+{
+ struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
+ u_int8_t val = 0;
+ int tempret, ret = 1;
+
+ tempret = ol_spectral_info_write(spectral,
+ OL_SPECTRAL_INFO_SPEC_ACTIVE,
+ &val,
+ sizeof(val));
+
+ if (tempret != 0)
+ ret = 0;
+
+ tempret = ol_spectral_info_write(spectral,
+ OL_SPECTRAL_INFO_SPEC_ENABLED,
+ &val,
+ sizeof(val));
+
+ if (tempret != 0)
+ ret = 0;
+
+ return ret;
+}
+
+/**
+ * target_if_spectral_get_extension_channel() - Get the current Extension
+ * channel (in MHz)
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * Return: Current Extension channel (in MHz) on success, 0 on failure or if
+ * extension channel is not present.
+ */
+u_int32_t target_if_spectral_get_extension_channel(void *arg)
+{
+ /* XXX: Once we expand to use cases where Spectral could be activated
+ * without a channel being set to VDEV, we need to consider returning a
+ * negative value in case of failure and having all callers handle this.
+ */
+
+ struct target_if_spectral *spectral = NULL;
+ struct wlan_objmgr_vdev *vdev = NULL;
+ u_int16_t sec20chan_freq = 0;
+
+ qdf_assert_always(arg);
+ spectral = (struct target_if_spectral *)arg;
+
+ vdev = target_if_spectral_get_vdev(spectral);
+ if (!vdev)
+ return 0;
+
+ if (wlan_vdev_get_sec20chan_freq_mhz(vdev, &sec20chan_freq) < 0) {
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
+ return 0;
+ }
+
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
+
+ return sec20chan_freq;
+}
+
+/**
+ * target_if_spectral_get_current_channel() - Get the current channel (in MHz)
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * Return: Current channel (in MHz) on success, 0 on failure
+ */
+u_int32_t target_if_spectral_get_current_channel(void *arg)
+{
+ /* XXX: Once we expand to use cases where Spectral could be activated
+ * without a channel being set to VDEV, we need to consider returning a
+ * negative value in case of failure and having all callers handle this.
+ */
+
+ struct target_if_spectral *spectral = NULL;
+ int16_t chan_freq = 0;
+ struct wlan_objmgr_vdev *vdev = NULL;
+
+ qdf_assert_always(arg);
+ spectral = (struct target_if_spectral *)arg;
+
+ vdev = target_if_spectral_get_vdev(spectral);
+ if (!vdev)
+ return 0;
+
+ chan_freq = wlan_vdev_get_chan_freq(vdev);
+ if (chan_freq < 0) {
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
+ return 0;
+ }
+
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
+
+ return chan_freq;
+}
+
+/**
+ * target_if_spectral_reset_hw() - Reset the hardware
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * This is only a placeholder since it is not currently required in the offload
+ * case.
+ *
+ * Return: 0
+ */
+u_int32_t target_if_spectral_reset_hw(void *arg)
+{
+ not_yet_implemented();
+ return 0;
+}
+
+/**
+ * target_if_spectral_get_chain_noise_floor() - Get the Chain noise floor from
+ * Noisefloor history buffer
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ * @nf_buf: Pointer to buffer into which chain Noise Floor data should be copied
+ *
+ * This is only a placeholder since it is not currently required in the offload
+ * case.
+ *
+ * Return: 0
+ */
+u_int32_t target_if_spectral_get_chain_noise_floor(void *arg, int16_t *nf_buf)
+{
+ not_yet_implemented();
+ return 0;
+}
+
+/**
+ * target_if_spectral_get_ext_noisefloor() - Get the extension channel
+ * noisefloor
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * This is only a placeholder since it is not currently required in the offload
+ * case.
+ *
+ * Return: 0
+ */
+int8_t target_if_spectral_get_ext_noisefloor(void *arg)
+{
+ not_yet_implemented();
+ return 0;
+}
+
+/**
+ * target_if_spectral_get_ctl_noisefloor() - Get the control channel noisefloor
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * This is only a placeholder since it is not currently required in the offload
+ * case.
+ *
+ * Return: 0
+ */
+int8_t target_if_spectral_get_ctl_noisefloor(void *arg)
+{
+ not_yet_implemented();
+ return 0;
+}
+
+/**
+ * target_if_spectral_configure_params() - Configure user supplied Spectral
+ * parameters
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ * @params: Spectral parameters
+ *
+ * Return: 1 on success, 0 on failure.
+ */
+u_int32_t target_if_spectral_configure_params(
+ void *arg,
+ struct spectral_config *params)
+{
+ struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
+ int ret;
+
+ ret = ol_spectral_info_write(spectral,
+ OL_SPECTRAL_INFO_SPEC_PARAMS,
+ params,
+ sizeof(*params));
+
+ if (ret != 0)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * target_if_spectral_get_params() - Get user configured Spectral parameters
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ * @params: Pointer to buffer into which Spectral parameters should be copied
+ *
+ * Return: 1 on success, 0 on failure.
+ */
+u_int32_t target_if_spectral_get_params(
+ void *arg,
+ struct spectral_config *params)
+{
+ struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
+ int ret;
+
+ ret = ol_spectral_info_read(spectral,
+ OL_SPECTRAL_INFO_SPEC_PARAMS,
+ params,
+ sizeof(*params));
+
+ if (ret != 0)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * target_if_spectral_get_ent_mask() - Get enterprise mask
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ *
+ * This is only a placeholder since it is not currently required in the offload
+ * case.
+ *
+ * Return: 0
+ */
+static u_int32_t target_if_spectral_get_ent_mask(void *arg)
+{
+ not_yet_implemented();
+ return 0;
+}
+
+/**
+ * target_if_spectral_get_macaddr() - Get radio MAC address
+ * @arg: Pointer to handle for Spectral target_if internal private data
+ * @addr: Pointer to buffer into which MAC address should be copied
+ *
+ * Return: 0 on success, -1 on failure
+ */
+static u_int32_t target_if_spectral_get_macaddr(void *arg, char *addr)
+{
+ uint8_t *myaddr = NULL;
+ struct target_if_spectral *spectral = (struct target_if_spectral *)arg;
+ struct wlan_objmgr_pdev *pdev = NULL;
+
+ pdev = spectral->pdev_obj;
+
+ wlan_pdev_obj_lock(pdev);
+ myaddr = wlan_pdev_get_hw_macaddr(pdev);
+ wlan_pdev_obj_unlock(pdev);
+ qdf_mem_copy(addr, myaddr, IEEE80211_ADDR_LEN);
+
+ return 0;
+}
+
+/**
+ * init_spectral_capability() - Initialize Spectral capability
+ * @spectral: Pointer to Spectral target_if internal private data
+ *
+ * This is a workaround.
+ *
+ * Return: None
+ */
+void init_spectral_capability(struct target_if_spectral *spectral)
+{
+ struct spectral_caps *pcap = &spectral->capability;
+
+ /* XXX : Workaround: Set Spectral capability */
+ pcap = &spectral->capability;
+ pcap->phydiag_cap = 1;
+ pcap->radar_cap = 1;
+ pcap->spectral_cap = 1;
+ pcap->advncd_spectral_cap = 1;
+}
+
+/**
+ * target_if_init_spectral_ops_common() - Initialize Spectral target_if internal
+ * operations common to all Spectral chipset generations
+ *
+ * Return: None
+ */
+void target_if_init_spectral_ops_common(void)
+{
+ struct target_if_spectral_ops *p_sops = &spectral_ops;
+
+ p_sops->get_tsf64 = target_if_spectral_get_tsf64;
+ p_sops->get_capability = target_if_spectral_get_capability;
+ p_sops->set_rxfilter = target_if_spectral_set_rxfilter;
+ p_sops->get_rxfilter = target_if_spectral_get_rxfilter;
+#if QCA_SUPPORT_SPECTRAL_SIMULATION
+ /* Spectral simulation is currently intended for platform transitions
+ * where underlying HW support may not be available for some time.
+ * Hence, we do not currently provide a runtime switch to turn the
+ * simulation on or off.
+ * In case of future requirements where runtime switches are required,
+ * this can be added. But it is suggested to use application layer
+ * simulation as far as possible in such cases, since the main
+ * use of record and replay of samples would concern higher
+ * level sample processing rather than lower level delivery.
+ */
+ p_sops->is_spectral_enabled = tif_spectral_sim_is_spectral_enabled;
+ p_sops->is_spectral_active = tif_spectral_sim_is_spectral_active;
+ p_sops->start_spectral_scan = tif_spectral_sim_start_spectral_scan;
+ p_sops->stop_spectral_scan = tif_spectral_sim_stop_spectral_scan;
+ p_sops->configure_spectral = tif_spectral_sim_configure_params;
+ p_sops->get_spectral_config = tif_spectral_sim_get_params;
+#else
+ p_sops->is_spectral_enabled = tgt_if_is_spectral_enabled;
+ p_sops->is_spectral_active = tgt_if_is_spectral_active;
+ p_sops->start_spectral_scan = tgt_if_start_spectral_scan;
+ p_sops->stop_spectral_scan = tgt_if_stop_spectral_scan;
+ p_sops->configure_spectral = target_if_spectral_configure_params;
+ p_sops->get_spectral_config = target_if_spectral_get_params;
+#endif /* QCA_SUPPORT_SPECTRAL_SIMULATION */
+ p_sops->get_extension_channel =
+ target_if_spectral_get_extension_channel;
+ p_sops->get_ctl_noisefloor =
+ target_if_spectral_get_ctl_noisefloor;
+ p_sops->get_ext_noisefloor =
+ target_if_spectral_get_ext_noisefloor;
+ p_sops->get_ent_spectral_mask = target_if_spectral_get_ent_mask;
+ p_sops->get_mac_address = target_if_spectral_get_macaddr;
+ p_sops->get_current_channel =
+ target_if_spectral_get_current_channel;
+ p_sops->reset_hw = target_if_spectral_reset_hw;
+ p_sops->get_chain_noise_floor =
+ target_if_spectral_get_chain_noise_floor;
+}
+
+/**
+ * target_if_init_spectral_ops_gen2() - Initialize Spectral target_if internal
+ * operations specific to Spectral chipset generation 2.
+ *
+ * Return: None
+ */
+void target_if_init_spectral_ops_gen2(void)
+{
+ struct target_if_spectral_ops *p_sops = &spectral_ops;
+
+ p_sops->spectral_process_phyerr = spectral_process_phyerr_gen2;
+}
+
+/**
+ * target_if_init_spectral_ops_gen3() - Initialize Spectral target_if internal
+ * operations specific to Spectral chipset generation 3.
+ *
+ * Return: None
+ */
+void target_if_init_spectral_ops_gen3(void)
+{
+ struct target_if_spectral_ops *p_sops = &spectral_ops;
+
+ p_sops->spectral_process_phyerr = spectral_process_phyerr_gen3;
+}
+
+/**
+ * target_if_init_spectral_ops() - Initialize target_if internal Spectral
+ * operations.
+ * @spectral: Pointer to Spectral target_if internal private data
+ *
+ * Return: None
+ */
+void target_if_init_spectral_ops(struct target_if_spectral *spectral)
+{
+ target_if_init_spectral_ops_common();
+ if (spectral->spectral_gen == SPECTRAL_GEN2)
+ target_if_init_spectral_ops_gen2();
+ else if (spectral->spectral_gen == SPECTRAL_GEN3)
+ target_if_init_spectral_ops_gen3();
+ else
+ qdf_print("Invalid spetral generation\n");
+}
+
+/*
+ * Dummy Functions:
+ * These functions are initially registered to avoid any crashes due to
+ * invocation of spectral functions before they are registered.
+ */
+
+static u_int64_t null_get_tsf64(void *arg)
+{
+ spectral_ops_not_registered("get_tsf64");
+ return 0;
+}
+
+static u_int32_t null_get_capability(void *arg, SPECTRAL_CAPABILITY_TYPE type)
+{
+ /*
+ * TODO : We should have conditional compilation to get the capability
+ * : We have not yet attahced ATH layer here, so there is no
+ * : way to check the HAL capbalities
+ */
+ spectral_ops_not_registered("get_capability");
+
+ /* TODO : For the time being, we are returning TRUE */
+ return true;
+}
+
+static u_int32_t null_set_rxfilter(void *arg, int rxfilter)
+{
+ spectral_ops_not_registered("set_rxfilter");
+ return 1;
+}
+
+static u_int32_t null_get_rxfilter(void *arg)
+{
+ spectral_ops_not_registered("get_rxfilter");
+ return 0;
+}
+
+static u_int32_t null_is_spectral_active(void *arg)
+{
+ spectral_ops_not_registered("is_spectral_active");
+ return 1;
+}
+
+static u_int32_t null_is_spectral_enabled(void *arg)
+{
+ spectral_ops_not_registered("is_spectral_enabled");
+ return 1;
+}
+
+static u_int32_t null_start_spectral_scan(void *arg)
+{
+ spectral_ops_not_registered("start_spectral_scan");
+ return 1;
+}
+
+static u_int32_t null_stop_spectral_scan(void *arg)
+{
+ spectral_ops_not_registered("stop_spectral_scan");
+ return 1;
+}
+
+static u_int32_t null_get_extension_channel(void *arg)
+{
+ spectral_ops_not_registered("get_extension_channel");
+ return 1;
+}
+
+static int8_t null_get_ctl_noisefloor(void *arg)
+{
+ spectral_ops_not_registered("get_ctl_noisefloor");
+ return 1;
+}
+
+static int8_t null_get_ext_noisefloor(void *arg)
+{
+ spectral_ops_not_registered("get_ext_noisefloor");
+ return 0;
+}
+
+static u_int32_t null_configure_spectral(
+ void *arg,
+ struct spectral_config *params)
+{
+ spectral_ops_not_registered("configure_spectral");
+ return 0;
+}
+
+static u_int32_t null_get_spectral_config(
+ void *arg,
+ struct spectral_config *params)
+{
+ spectral_ops_not_registered("get_spectral_config");
+ return 0;
+}
+
+static u_int32_t null_get_ent_spectral_mask(void *arg)
+{
+ spectral_ops_not_registered("get_ent_spectral_mask");
+ return 0;
+}
+
+static u_int32_t null_get_mac_address(void *arg, char *addr)
+{
+ spectral_ops_not_registered("get_mac_address");
+ return 0;
+}
+
+static u_int32_t null_get_current_channel(void *arg)
+{
+ spectral_ops_not_registered("get_current_channel");
+ return 0;
+}
+
+static u_int32_t null_reset_hw(void *arg)
+{
+ spectral_ops_not_registered("get_current_channel");
+ return 0;
+}
+
+static u_int32_t null_get_chain_noise_floor(void *arg, int16_t *nf_buf)
+{
+ spectral_ops_not_registered("get_chain_noise_floor");
+ return 0;
+}
+
+static int null_spectral_process_phyerr(
+ struct target_if_spectral *spectral,
+ u_int8_t *data,
+ u_int32_t datalen,
+ struct target_if_spectral_rfqual_info *p_rfqual,
+ struct target_if_spectral_chan_info *p_chaninfo,
+ u_int64_t tsf64,
+ struct target_if_spectral_acs_stats *acs_stats)
+{
+ spectral_ops_not_registered("spectral_process_phyerr");
+ return 0;
+}
+
+/**
+ * target_if_spectral_init_dummy_function_table() -
+ * Initialize target_if internal
+ * Spectral operations to dummy functions
+ * @ps: Pointer to Spectral target_if internal private data
+ *
+ * Return: None
+ */
+void target_if_spectral_init_dummy_function_table(
+ struct target_if_spectral *ps)
+{
+ struct target_if_spectral_ops *p_sops = GET_TIF_SPECTRAL_OPS(ps);
+
+ p_sops->get_tsf64 = null_get_tsf64;
+ p_sops->get_capability = null_get_capability;
+ p_sops->set_rxfilter = null_set_rxfilter;
+ p_sops->get_rxfilter = null_get_rxfilter;
+ p_sops->is_spectral_enabled = null_is_spectral_enabled;
+ p_sops->is_spectral_active = null_is_spectral_active;
+ p_sops->start_spectral_scan = null_start_spectral_scan;
+ p_sops->stop_spectral_scan = null_stop_spectral_scan;
+ p_sops->get_extension_channel = null_get_extension_channel;
+ p_sops->get_ctl_noisefloor = null_get_ctl_noisefloor;
+ p_sops->get_ext_noisefloor = null_get_ext_noisefloor;
+ p_sops->configure_spectral = null_configure_spectral;
+ p_sops->get_spectral_config = null_get_spectral_config;
+ p_sops->get_ent_spectral_mask = null_get_ent_spectral_mask;
+ p_sops->get_mac_address = null_get_mac_address;
+ p_sops->get_current_channel = null_get_current_channel;
+ p_sops->reset_hw = null_reset_hw;
+ p_sops->get_chain_noise_floor = null_get_chain_noise_floor;
+ p_sops->spectral_process_phyerr = null_spectral_process_phyerr;
+}
+
+/**
+ * target_if_spectral_register_funcs() - Initialize target_if internal Spectral
+ * operations
+ * @spectral: Pointer to Spectral target_if internal private data
+ * @p: Pointer to Spectral function table
+ *
+ * Return: None
+ */
+void target_if_spectral_register_funcs(
+ struct target_if_spectral *spectral,
+ struct target_if_spectral_ops *p)
+{
+ struct target_if_spectral_ops *p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+
+ p_sops->get_tsf64 = p->get_tsf64;
+ p_sops->get_capability = p->get_capability;
+ p_sops->set_rxfilter = p->set_rxfilter;
+ p_sops->get_rxfilter = p->get_rxfilter;
+ p_sops->is_spectral_enabled = p->is_spectral_enabled;
+ p_sops->is_spectral_active = p->is_spectral_active;
+ p_sops->start_spectral_scan = p->start_spectral_scan;
+ p_sops->stop_spectral_scan = p->stop_spectral_scan;
+ p_sops->get_extension_channel = p->get_extension_channel;
+ p_sops->get_ctl_noisefloor = p->get_ctl_noisefloor;
+ p_sops->get_ext_noisefloor = p->get_ext_noisefloor;
+ p_sops->configure_spectral = p->configure_spectral;
+ p_sops->get_spectral_config = p->get_spectral_config;
+ p_sops->get_ent_spectral_mask = p->get_ent_spectral_mask;
+ p_sops->get_mac_address = p->get_mac_address;
+ p_sops->get_current_channel = p->get_current_channel;
+ p_sops->reset_hw = p->reset_hw;
+ p_sops->get_chain_noise_floor = p->get_chain_noise_floor;
+ p_sops->spectral_process_phyerr = p->spectral_process_phyerr;
+}
+
+/**
+ * target_if_spectral_clear_stats() - Clear Spectral stats
+ * @spectral: Pointer to Spectral target_if internal private data
+ *
+ * Return: None
+ */
+void target_if_spectral_clear_stats(struct target_if_spectral *spectral)
+{
+ struct target_if_spectral_ops *p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+
+ qdf_mem_zero(
+ &spectral->ath_spectral_stats,
+ sizeof(struct target_if_spectral_stats));
+ spectral->ath_spectral_stats.last_reset_tstamp =
+ p_sops->get_tsf64(spectral);
+}
+
+/**
+ * target_if_spectral_check_hw_capability() - Check whether HW supports spectral
+ * @spectral: Pointer to Spectral target_if internal private data
+ *
+ * Return: True if HW supports Spectral, false if HW does not support Spectral
+ */
+int target_if_spectral_check_hw_capability(struct target_if_spectral *spectral)
+{
+ struct target_if_spectral_ops *p_sops = NULL;
+ struct spectral_caps *pcap = NULL;
+ int is_spectral_supported = true;
+
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+ pcap = &spectral->capability;
+
+ if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG) == false) {
+ is_spectral_supported = false;
+ qdf_print("SPECTRAL : No PHYDIAG support\n");
+ return is_spectral_supported;
+ }
+ pcap->phydiag_cap = 1;
+
+ if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR) == false) {
+ is_spectral_supported = false;
+ qdf_print("SPECTRAL : No RADAR support\n");
+ return is_spectral_supported;
+ }
+ pcap->radar_cap = 1;
+
+ if (
+ p_sops->get_capability(spectral,
+ SPECTRAL_CAP_SPECTRAL_SCAN) == false) {
+ is_spectral_supported = false;
+ qdf_print("SPECTRAL : No SPECTRAL SUPPORT\n");
+ return is_spectral_supported;
+ }
+ pcap->spectral_cap = 1;
+
+ if (p_sops->get_capability(spectral, SPECTRAL_CAP_ADVNCD_SPECTRAL_SCAN)
+ == false) {
+ qdf_print("SPECTRAL : No ADVANCED SPECTRAL SUPPORT\n");
+ } else {
+ pcap->advncd_spectral_cap = 1;
+ }
+
+ return is_spectral_supported;
+}
+
+/**
+ * target_if_pdev_spectral_init() - Initialize Spectral parameter defaults
+ * @spectral: Pointer to Spectral target_if internal private data
+ *
+ * It is the caller's responsibility to ensure that the Spectral parameters
+ * structure passed as part of Spectral target_if internal private data is
+ * valid.
+ *
+ * Return: None
+ */
+static void target_if_spectral_init_param_defaults(
+ struct target_if_spectral *spectral)
+{
+ struct spectral_config *params = &spectral->params;
+
+ params->ss_count = SPECTRAL_SCAN_COUNT_DEFAULT;
+ params->ss_period = SPECTRAL_SCAN_PERIOD_DEFAULT;
+ params->ss_spectral_pri = SPECTRAL_SCAN_PRIORITY_DEFAULT;
+ params->ss_fft_size = SPECTRAL_SCAN_FFT_SIZE_DEFAULT;
+ params->ss_gc_ena = SPECTRAL_SCAN_GC_ENA_DEFAULT;
+ params->ss_restart_ena = SPECTRAL_SCAN_RESTART_ENA_DEFAULT;
+ params->ss_noise_floor_ref = SPECTRAL_SCAN_NOISE_FLOOR_REF_DEFAULT;
+ params->ss_init_delay = SPECTRAL_SCAN_INIT_DELAY_DEFAULT;
+ params->ss_nb_tone_thr = SPECTRAL_SCAN_NB_TONE_THR_DEFAULT;
+ params->ss_str_bin_thr = SPECTRAL_SCAN_STR_BIN_THR_DEFAULT;
+ params->ss_wb_rpt_mode = SPECTRAL_SCAN_WB_RPT_MODE_DEFAULT;
+ params->ss_rssi_rpt_mode = SPECTRAL_SCAN_RSSI_RPT_MODE_DEFAULT;
+ params->ss_rssi_thr = SPECTRAL_SCAN_RSSI_THR_DEFAULT;
+ params->ss_pwr_format = SPECTRAL_SCAN_PWR_FORMAT_DEFAULT;
+ params->ss_rpt_mode = SPECTRAL_SCAN_RPT_MODE_DEFAULT;
+ params->ss_bin_scale = SPECTRAL_SCAN_BIN_SCALE_DEFAULT;
+ params->ss_dBm_adj = SPECTRAL_SCAN_DBM_ADJ_DEFAULT;
+ /*
+ * XXX
+ * SPECTRAL_SCAN_CHN_MASK_DEFAULT (0x1) specifies that chain 0 is to be
+ * used
+ * for Spectral. This is expected to be an optimal configuration for
+ * most chipsets considering aspects like power save. But this can later
+ * optionally be changed to be set to the default system Rx chainmask
+ * advertised by FW (if required for some purpose), once the Convergence
+ * framework supports such retrieval at pdev attach time.
+ */
+ params->ss_chn_mask = SPECTRAL_SCAN_CHN_MASK_DEFAULT;
+ params->ss_short_report = SPECTRAL_SCAN_SHORT_REPORT_DEFAULT;
+ params->ss_fft_period = SPECTRAL_SCAN_FFT_PERIOD_DEFAULT;
+}
+
+/**
+ * target_if_spectral_detach() - De-initialize target_if Spectral
+ * @pdev: Pointer to pdev object
+ *
+ * Return: None
+ */
+static void target_if_spectral_detach(struct target_if_spectral *spectral)
+{
+ qdf_print("spectral detach\n");
+ qdf_spinlock_destroy(&spectral->ol_info.osps_lock);
+
+#if QCA_SUPPORT_SPECTRAL_SIMULATION
+ target_if_spectral_sim_detach(spectral);
+#endif /* QCA_SUPPORT_SPECTRAL_SIMULATION */
+
+#ifdef SPECTRAL_USE_NETLINK_SOCKETS
+ target_if_spectral_destroy_netlink(spectral);
+#endif
+
+ qdf_spinlock_destroy(&spectral->ath_spectral_lock);
+ qdf_spinlock_destroy(&spectral->noise_pwr_reports_lock);
+
+ if (spectral) {
+ qdf_mem_free(spectral);
+ spectral = NULL;
+ }
+}
+
+/**
+ * target_if_pdev_spectral_init() - Initialize target_if Spectral
+ * functionality for the given pdev
+ * @pdev: Pointer to pdev object
+ *
+ * Return: On success, pointer to Spectral target_if internal private data, on
+ * failure, NULL
+ */
+void *target_if_pdev_spectral_init(struct wlan_objmgr_pdev *pdev)
+{
+ struct target_if_spectral_ops *p_sops = NULL;
+ struct target_if_spectral *spectral = NULL;
+ struct ol_ath_softc_net80211 *scn = NULL;
+ struct pdev_osif_priv *osif_priv = NULL;
+
+ osif_priv = wlan_pdev_get_ospriv(pdev);
+ scn = (struct ol_ath_softc_net80211 *)osif_priv->legacy_osif_priv;
+ if (!scn) {
+ qdf_print("%s: scn is NULL!\n", __func__);
+ return NULL;
+ }
+
+ spectral = (struct target_if_spectral *)qdf_mem_malloc(
+ sizeof(struct target_if_spectral));
+ if (!spectral) {
+ qdf_print("SPECTRAL : Memory allocation failed\n");
+ return spectral;
+ }
+ qdf_mem_zero(spectral, sizeof(struct target_if_spectral));
+ /* Store pdev in Spectral */
+ spectral->pdev_obj = pdev;
+
+ /* init the function ptr table */
+ target_if_spectral_init_dummy_function_table(spectral);
+
+ /* get spectral function table */
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+ /* TODO : Should this be called here of after ath_attach ? */
+ if (p_sops->get_capability(spectral, SPECTRAL_CAP_PHYDIAG))
+ qdf_print(KERN_INFO "HAL_CAP_PHYDIAG : Capable\n");
+
+ SPECTRAL_TODO("Need to fix the capablity check for RADAR");
+ if (p_sops->get_capability(spectral, SPECTRAL_CAP_RADAR))
+ qdf_print(KERN_INFO "HAL_CAP_RADAR : Capable\n");
+
+ SPECTRAL_TODO("Need to fix the capablity check for SPECTRAL\n");
+ /* TODO : Should this be called here of after ath_attach ? */
+ if (p_sops->get_capability(spectral, SPECTRAL_CAP_SPECTRAL_SCAN))
+ qdf_print(KERN_INFO "HAL_CAP_SPECTRAL_SCAN : Capable\n");
+
+ qdf_spinlock_create(&spectral->ath_spectral_lock);
+ qdf_spinlock_create(&spectral->noise_pwr_reports_lock);
+ target_if_spectral_clear_stats(spectral);
+
+ qdf_spinlock_create(&spectral->spectral_skbqlock);
+ STAILQ_INIT(&spectral->spectral_skbq);
+
+#ifdef SPECTRAL_USE_NETLINK_SOCKETS
+ target_if_spectral_init_netlink(spectral);
+#endif
+
+ /* Set the default values for spectral parameters */
+ target_if_spectral_init_param_defaults(spectral);
+
+ if ((scn->soc->target_type == TARGET_TYPE_QCA8074) || (
+ scn->soc->target_type == TARGET_TYPE_QCA6290)) {
+ spectral->spectral_gen = SPECTRAL_GEN3;
+ spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN3;
+ spectral->tag_sscan_summary_exp =
+ TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3;
+ spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN3;
+ spectral->tlvhdr_size = SPECTRAL_PHYERR_TLVSIZE_GEN3;
+ } else {
+ spectral->spectral_gen = SPECTRAL_GEN2;
+ spectral->hdr_sig_exp = SPECTRAL_PHYERR_SIGNATURE_GEN2;
+ spectral->tag_sscan_summary_exp =
+ TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2;
+ spectral->tag_sscan_fft_exp = TLV_TAG_SEARCH_FFT_REPORT_GEN2;
+ spectral->tlvhdr_size = sizeof(SPECTRAL_PHYERR_TLV_GEN2);
+ }
+
+#if QCA_SUPPORT_SPECTRAL_SIMULATION
+ if (target_if_spectral_sim_attach(spectral)) {
+ qdf_mem_free(spectral);
+ return NULL;
+ }
+#endif /* QCA_SUPPORT_SPECTRAL_SIMULATION */
+ target_if_init_spectral_ops(spectral);
+
+ qdf_spinlock_create(&spectral->ol_info.osps_lock);
+ spectral->ol_info.osps_cache.osc_is_valid = 0;
+
+ target_if_spectral_register_funcs(spectral, &spectral_ops);
+
+ if (target_if_spectral_check_hw_capability(spectral) == false) {
+ target_if_spectral_detach(spectral);
+ spectral = NULL;
+ } else {
+ /* TODO: Once the driver architecture transitions to chipset
+ * versioning based checks, reflect this here.
+ */
+ spectral->is_160_format = false;
+ spectral->is_lb_edge_extrabins_format = false;
+ spectral->is_rb_edge_extrabins_format = false;
+
+ if (scn->soc->target_type == TARGET_TYPE_QCA9984 ||
+ scn->soc->target_type == TARGET_TYPE_QCA9888) {
+ spectral->is_160_format = true;
+ spectral->is_lb_edge_extrabins_format = true;
+ spectral->is_rb_edge_extrabins_format = true;
+ } else if ((scn->soc->target_type == TARGET_TYPE_AR900B) &&
+ (scn->soc->target_revision == AR900B_REV_2)) {
+ spectral->is_rb_edge_extrabins_format = true;
+ }
+
+ if (scn->soc->target_type == TARGET_TYPE_QCA9984 ||
+ scn->soc->target_type == TARGET_TYPE_QCA9888)
+ spectral->is_sec80_rssi_war_required = true;
+ }
+
+ return spectral;
+}
+
+/**
+ * target_if_pdev_spectral_init() - De-initialize target_if Spectral
+ * functionality for the given pdev
+ * @pdev: Pointer to pdev object
+ *
+ * Return: None
+ */
+static void target_if_pdev_spectral_deinit(struct wlan_objmgr_pdev *pdev)
+{
+ struct target_if_spectral *spectral = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ if (!spectral) {
+ qdf_print("SPECTRAL : Module doesn't exist\n");
+ return;
+ }
+ target_if_spectral_detach(spectral);
+}
+
+/**
+ * target_if_set_spectral_config() - Set spectral config
+ * @pdev: Pointer to pdev object
+ * @threshtype: config type
+ * @value: config value
+ *
+ * API to set spectral configurations
+ *
+ * Return: 1 on success, 0 on failure
+ */
+static int target_if_set_spectral_config(struct wlan_objmgr_pdev *pdev,
+ const u_int32_t threshtype,
+ const u_int32_t value)
+{
+ struct spectral_config params;
+ struct target_if_spectral_ops *p_sops = NULL;
+ struct target_if_spectral *spectral = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+ if (!spectral) {
+ qdf_print("%s: spectral object is NULL\n", __func__);
+ return 0;
+ }
+
+ switch (threshtype) {
+ case SPECTRAL_PARAM_FFT_PERIOD:
+ spectral->params.ss_fft_period = value;
+ break;
+ case SPECTRAL_PARAM_SCAN_PERIOD:
+ spectral->params.ss_period = value;
+ break;
+ case SPECTRAL_PARAM_SCAN_COUNT:
+ spectral->params.ss_count = value;
+ break;
+ case SPECTRAL_PARAM_SHORT_REPORT:
+ spectral->params.ss_short_report = (!!value) ? true : false;
+ break;
+ case SPECTRAL_PARAM_SPECT_PRI:
+ spectral->params.ss_spectral_pri = (!!value) ? true : false;
+ break;
+ case SPECTRAL_PARAM_FFT_SIZE:
+ spectral->params.ss_fft_size = value;
+ break;
+ case SPECTRAL_PARAM_GC_ENA:
+ spectral->params.ss_gc_ena = !!value;
+ break;
+ case SPECTRAL_PARAM_RESTART_ENA:
+ spectral->params.ss_restart_ena = !!value;
+ break;
+ case SPECTRAL_PARAM_NOISE_FLOOR_REF:
+ spectral->params.ss_noise_floor_ref = value;
+ break;
+ case SPECTRAL_PARAM_INIT_DELAY:
+ spectral->params.ss_init_delay = value;
+ break;
+ case SPECTRAL_PARAM_NB_TONE_THR:
+ spectral->params.ss_nb_tone_thr = value;
+ break;
+ case SPECTRAL_PARAM_STR_BIN_THR:
+ spectral->params.ss_str_bin_thr = value;
+ break;
+ case SPECTRAL_PARAM_WB_RPT_MODE:
+ spectral->params.ss_wb_rpt_mode = !!value;
+ break;
+ case SPECTRAL_PARAM_RSSI_RPT_MODE:
+ spectral->params.ss_rssi_rpt_mode = !!value;
+ break;
+ case SPECTRAL_PARAM_RSSI_THR:
+ spectral->params.ss_rssi_thr = value;
+ break;
+ case SPECTRAL_PARAM_PWR_FORMAT:
+ spectral->params.ss_pwr_format = !!value;
+ break;
+ case SPECTRAL_PARAM_RPT_MODE:
+ spectral->params.ss_rpt_mode = value;
+ break;
+ case SPECTRAL_PARAM_BIN_SCALE:
+ spectral->params.ss_bin_scale = value;
+ break;
+ case SPECTRAL_PARAM_DBM_ADJ:
+ spectral->params.ss_dBm_adj = !!value;
+ break;
+ case SPECTRAL_PARAM_CHN_MASK:
+ spectral->params.ss_chn_mask = value;
+ break;
+ }
+
+ p_sops->configure_spectral(spectral, &spectral->params);
+ /* only to validate the writes */
+ p_sops->get_spectral_config(spectral, ¶ms);
+ /* print_spectral_params(&spectral->params); */
+ return 1;
+}
+
+static int get_fft_bin_count(int fft_len)
+{
+ int bin_count = 0;
+
+ switch (fft_len) {
+ case 5:
+ bin_count = 16;
+ break;
+ case 6:
+ bin_count = 32;
+ break;
+ case 7:
+ bin_count = 64;
+ break;
+ case 8:
+ bin_count = 128;
+ break;
+ case 9:
+ bin_count = 256;
+ break;
+ default:
+ break;
+ }
+
+ return bin_count;
+}
+
+static void init_upper_lower_flags(struct target_if_spectral *spectral)
+{
+ int current_channel = 0;
+ int ext_channel = 0;
+ struct target_if_spectral_ops *p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+
+ current_channel = p_sops->get_current_channel(spectral);
+ ext_channel = p_sops->get_extension_channel(spectral);
+
+ if ((current_channel == 0) || (ext_channel == 0))
+ return;
+
+ if (spectral->sc_spectral_20_40_mode) {
+ /* HT40 mode */
+ if (ext_channel < current_channel) {
+ spectral->lower_is_extension = 1;
+ spectral->upper_is_control = 1;
+ spectral->lower_is_control = 0;
+ spectral->upper_is_extension = 0;
+ } else {
+ spectral->lower_is_extension = 0;
+ spectral->upper_is_control = 0;
+ spectral->lower_is_control = 1;
+ spectral->upper_is_extension = 1;
+ }
+ } else {
+ /* HT20 mode, lower is always control */
+ spectral->lower_is_extension = 0;
+ spectral->upper_is_control = 0;
+ spectral->lower_is_control = 1;
+ spectral->upper_is_extension = 0;
+ }
+}
+
+/**
+ * target_if_get_spectral_config() - Get spectral configuration
+ * @pdev: Pointer to pdev object
+ * @param: Pointer to spectral_config structure in which the configuration
+ * should be returned
+ *
+ * API to get the current spectral configuration
+ *
+ * Return: 1 on success, 0 on failure.
+ */
+static void target_if_get_spectral_config(struct wlan_objmgr_pdev *pdev,
+ struct spectral_config *param)
+{
+ struct target_if_spectral_ops *p_sops = NULL;
+ struct target_if_spectral *spectral = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+
+ qdf_mem_zero(param, sizeof(struct spectral_config));
+ p_sops->get_spectral_config(spectral, param);
+}
+
+/**
+ * target_if_spectral_scan_enable_params() - Enable use of desired Spectral
+ * parameters
+ * @spectral: Pointer to Spectral target_if internal private data
+ * @spectral_params: Pointer to Spectral parameters
+ *
+ * Enable use of desired Spectral parameters by configuring them into HW, and
+ * starting Spectral scan
+ *
+ * Return: 0 on success, 1 on failure
+ */
+static int target_if_spectral_scan_enable_params(
+ struct target_if_spectral *spectral,
+ struct spectral_config *spectral_params)
+{
+ int extension_channel = 0;
+ int current_channel = 0;
+ struct target_if_spectral_ops *p_sops = NULL;
+ struct ol_ath_softc_net80211 *scn = NULL;
+ struct pdev_osif_priv *osif_priv = NULL;
+ struct wlan_objmgr_pdev *pdev = spectral->pdev_obj;
+ struct wlan_objmgr_vdev *vdev = NULL;
+
+ osif_priv = wlan_pdev_get_ospriv(pdev);
+ scn = (struct ol_ath_softc_net80211 *)osif_priv->legacy_osif_priv;
+
+ if (!spectral) {
+ qdf_print("SPECTRAL : Spectral is NULL\n");
+ return 1;
+ }
+
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+
+ if (!p_sops) {
+ qdf_print("SPECTRAL : p_sops is NULL\n");
+ return 1;
+ }
+
+ spectral->sc_spectral_noise_pwr_cal =
+ spectral_params->ss_spectral_pri ? 1 : 0;
+
+ /* check if extension channel is present */
+ extension_channel = p_sops->get_extension_channel(spectral);
+ current_channel = p_sops->get_current_channel(spectral);
+
+ vdev = target_if_spectral_get_vdev(spectral);
+ if (!vdev)
+ return 1;
+
+ spectral->ch_width = wlan_vdev_get_ch_width(vdev);
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
+
+ if (spectral->ch_width == CH_WIDTH_INVALID)
+ return 1;
+
+ if (spectral->capability.advncd_spectral_cap) {
+ spectral->lb_edge_extrabins = 0;
+ spectral->rb_edge_extrabins = 0;
+
+ if (spectral->is_lb_edge_extrabins_format &&
+ spectral->params.ss_rpt_mode == 2) {
+ spectral->lb_edge_extrabins = 4;
+ }
+
+ if (spectral->is_rb_edge_extrabins_format &&
+ spectral->params.ss_rpt_mode == 2) {
+ spectral->rb_edge_extrabins = 4;
+ }
+
+ if (spectral->ch_width == IEEE80211_CWM_WIDTH20) {
+ /* qdf_print("SPECTRAL : (11AC) 20MHz Channel Width
+ * (Channel = %d)\n", current_channel);
+ */
+ spectral->sc_spectral_20_40_mode = 0;
+
+ spectral->spectral_numbins =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+ spectral->spectral_fft_len =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+ spectral->spectral_data_len =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+ /* Initialize classifier params to be sent to user
+ * space classifier
+ */
+ spectral->classifier_params.lower_chan_in_mhz =
+ current_channel;
+ spectral->classifier_params.upper_chan_in_mhz = 0;
+
+ } else if (spectral->ch_width == IEEE80211_CWM_WIDTH40) {
+ /* qdf_print("SPECTRAL : (11AC) 40MHz Channel Width
+ * (Channel = %d)\n", current_channel);
+ */
+ spectral->sc_spectral_20_40_mode =
+ 1; /* TODO : Remove this variable */
+ spectral->spectral_numbins =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+ spectral->spectral_fft_len =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+ spectral->spectral_data_len =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+
+ /* Initialize classifier params to be sent to user
+ * space classifier
+ */
+ if (extension_channel < current_channel) {
+ spectral->classifier_params.lower_chan_in_mhz =
+ extension_channel;
+ spectral->classifier_params.upper_chan_in_mhz =
+ current_channel;
+ } else {
+ spectral->classifier_params.lower_chan_in_mhz =
+ current_channel;
+ spectral->classifier_params.upper_chan_in_mhz =
+ extension_channel;
+ }
+
+ } else if (spectral->ch_width == IEEE80211_CWM_WIDTH80) {
+ /* qdf_print("SPECTRAL : (11AC) 80MHz Channel Width
+ * (Channel = %d)\n", current_channel);
+ */
+ /* Set the FFT Size */
+ spectral->sc_spectral_20_40_mode =
+ 0; /* TODO : Remove this variable */
+ spectral->spectral_numbins =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+ spectral->spectral_fft_len =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+ spectral->spectral_data_len =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+
+ /* Initialize classifier params to be sent to user
+ * space classifier
+ */
+ spectral->classifier_params.lower_chan_in_mhz =
+ current_channel;
+ spectral->classifier_params.upper_chan_in_mhz = 0;
+
+ /* Initialize classifier params to be sent to user
+ * space classifier
+ */
+ if (extension_channel < current_channel) {
+ spectral->classifier_params.lower_chan_in_mhz =
+ extension_channel;
+ spectral->classifier_params.upper_chan_in_mhz =
+ current_channel;
+ } else {
+ spectral->classifier_params.lower_chan_in_mhz =
+ current_channel;
+ spectral->classifier_params.upper_chan_in_mhz =
+ extension_channel;
+ }
+
+ } else if (spectral->ch_width == IEEE80211_CWM_WIDTH160) {
+ /* qdf_print("SPECTRAL : (11AC) 160MHz Channel Width
+ * (Channel = %d)\n", current_channel);
+ */
+ /* Set the FFT Size */
+
+ /* The below applies to both 160 and 80+80 cases */
+
+ spectral->sc_spectral_20_40_mode =
+ 0; /* TODO : Remove this variable */
+ spectral->spectral_numbins =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+ spectral->spectral_fft_len =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+ spectral->spectral_data_len =
+ get_fft_bin_count(spectral->params.ss_fft_size);
+
+ /* Initialize classifier params to be sent to user
+ * space classifier
+ */
+ spectral->classifier_params.lower_chan_in_mhz =
+ current_channel;
+ spectral->classifier_params.upper_chan_in_mhz = 0;
+
+ /* Initialize classifier params to be sent to user
+ * space classifier
+ */
+ if (extension_channel < current_channel) {
+ spectral->classifier_params.lower_chan_in_mhz =
+ extension_channel;
+ spectral->classifier_params.upper_chan_in_mhz =
+ current_channel;
+ } else {
+ spectral->classifier_params.lower_chan_in_mhz =
+ current_channel;
+ spectral->classifier_params.upper_chan_in_mhz =
+ extension_channel;
+ }
+ }
+
+ if (spectral->spectral_numbins) {
+ spectral->spectral_numbins +=
+ spectral->lb_edge_extrabins;
+ spectral->spectral_numbins +=
+ spectral->rb_edge_extrabins;
+ }
+
+ if (spectral->spectral_fft_len) {
+ spectral->spectral_fft_len +=
+ spectral->lb_edge_extrabins;
+ spectral->spectral_fft_len +=
+ spectral->rb_edge_extrabins;
+ }
+
+ if (spectral->spectral_data_len) {
+ spectral->spectral_data_len +=
+ spectral->lb_edge_extrabins;
+ spectral->spectral_data_len +=
+ spectral->rb_edge_extrabins;
+ }
+ } else {
+ /* qdf_print("SPECTRAL : Legacy (Non-11AC)\n"); */
+ /*
+ * The decision to find 20/40 mode is found based on the
+ * presence of extension channel
+ * instead of channel width, as the channel width can
+ * dynamically change
+ */
+
+ if (extension_channel == 0) {
+ /* qdf_print("SPECTRAL : (Legacy) 20MHz Channel Width
+ * (Channel = %d)\n", current_channel);
+ */
+ spectral->spectral_numbins =
+ SPECTRAL_HT20_NUM_BINS;
+ spectral->spectral_dc_index =
+ SPECTRAL_HT20_DC_INDEX;
+ spectral->spectral_fft_len =
+ SPECTRAL_HT20_FFT_LEN;
+ spectral->spectral_data_len =
+ SPECTRAL_HT20_TOTAL_DATA_LEN;
+ spectral->spectral_lower_max_index_offset =
+ -1; /* only valid in 20-40 mode */
+ spectral->spectral_upper_max_index_offset =
+ -1; /* only valid in 20-40 mode */
+ spectral->spectral_max_index_offset =
+ spectral->spectral_fft_len + 2;
+ spectral->sc_spectral_20_40_mode = 0;
+
+ /* Initialize classifier params to be sent to user
+ * space classifier
+ */
+ spectral->classifier_params.lower_chan_in_mhz =
+ current_channel;
+ spectral->classifier_params.upper_chan_in_mhz = 0;
+
+ } else {
+ /* qdf_print("SPECTRAL : (Legacy) 40MHz Channel Width
+ * (Channel = %d)\n", current_channel);
+ */
+ spectral->spectral_numbins =
+ SPECTRAL_HT40_TOTAL_NUM_BINS;
+ spectral->spectral_fft_len =
+ SPECTRAL_HT40_FFT_LEN;
+ spectral->spectral_data_len =
+ SPECTRAL_HT40_TOTAL_DATA_LEN;
+ spectral->spectral_dc_index =
+ SPECTRAL_HT40_DC_INDEX;
+ spectral->spectral_max_index_offset =
+ -1; /* only valid in 20 mode */
+ spectral->spectral_lower_max_index_offset =
+ spectral->spectral_fft_len + 2;
+ spectral->spectral_upper_max_index_offset =
+ spectral->spectral_fft_len + 5;
+ spectral->sc_spectral_20_40_mode = 1;
+
+ /* Initialize classifier params to be sent to user
+ * space classifier
+ */
+ if (extension_channel < current_channel) {
+ spectral->classifier_params.lower_chan_in_mhz =
+ extension_channel;
+ spectral->classifier_params.upper_chan_in_mhz =
+ current_channel;
+ } else {
+ spectral->classifier_params.lower_chan_in_mhz =
+ current_channel;
+ spectral->classifier_params.upper_chan_in_mhz =
+ extension_channel;
+ }
+ }
+ }
+
+ spectral->send_single_packet = 0;
+ spectral->classifier_params.spectral_20_40_mode =
+ spectral->sc_spectral_20_40_mode;
+ spectral->classifier_params.spectral_dc_index =
+ spectral->spectral_dc_index;
+ spectral->spectral_sent_msg = 0;
+ spectral->classify_scan = 0;
+ spectral->num_spectral_data = 0;
+
+ if (!p_sops->is_spectral_active(spectral)) {
+ p_sops->configure_spectral(spectral, spectral_params);
+ p_sops->start_spectral_scan(spectral);
+ /* qdf_print("Enabled spectral scan on channel %d\n",
+ * p_sops->get_current_channel(spectral));
+ */
+ } else {
+ /* qdf_print("Spectral scan is already ACTIVE on channel %d\n",
+ * p_sops->get_current_channel(spectral));
+ */
+ }
+
+ /* get current spectral configuration */
+ p_sops->get_spectral_config(spectral, &spectral->params);
+
+ init_upper_lower_flags(spectral);
+
+#ifdef SPECTRAL_CLASSIFIER_IN_KERNEL
+ init_classifier(sc);
+#endif
+ return 0;
+}
+
+/**
+ * target_if_start_spectral_scan() - Start spectral scan
+ * @pdev: Pointer to pdev object
+ *
+ * API to start spectral scan
+ *
+ * Return: 0 in case of success, -1 on failure
+ */
+static int target_if_start_spectral_scan(struct wlan_objmgr_pdev *pdev)
+{
+ struct target_if_spectral_ops *p_sops = NULL;
+ struct target_if_spectral *spectral = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ if (!spectral) {
+ qdf_print("SPECTRAL : Spectral LMAC object is NUll (%s)\n",
+ __func__);
+ return -EPERM;
+ }
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+
+ qdf_spin_lock(&spectral->ath_spectral_lock);
+ target_if_spectral_scan_enable_params(spectral, &spectral->params);
+ qdf_spin_unlock(&spectral->ath_spectral_lock);
+
+ return 0;
+}
+
+/**
+ * target_if_stop_spectral_scan() - Stop spectral scan
+ * @pdev: Pointer to pdev object
+ *
+ * API to stop the current on-going spectral scan
+ *
+ * Return: None
+ */
+void target_if_stop_spectral_scan(struct wlan_objmgr_pdev *pdev)
+{
+ struct target_if_spectral_ops *p_sops = NULL;
+ struct target_if_spectral *spectral = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ if (!spectral) {
+ qdf_print("SPECTRAL : Spectral LMAC object is NUll (%s)\n",
+ __func__);
+ return;
+ }
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+
+ qdf_spin_lock(&spectral->ath_spectral_lock);
+ p_sops->stop_spectral_scan(spectral);
+ if (spectral->classify_scan) {
+ SPECTRAL_TODO("Check if this logic is necessary");
+ spectral->detects_control_channel = 0;
+ spectral->detects_extension_channel = 0;
+ spectral->detects_above_dc = 0;
+ spectral->detects_below_dc = 0;
+ spectral->classify_scan = 0;
+ }
+
+ spectral->send_single_packet = 0;
+ spectral->sc_spectral_scan = 0;
+ spectral->sc_spectral_noise_pwr_cal = 0;
+
+ /*
+ * Reset the priority because it stops WLAN rx.
+ * If it is needed to set, user has to set it explicitly
+ *
+ */
+ /* Reset Priority */
+ spectral->params.ss_spectral_pri = 0;
+ qdf_spin_unlock(&spectral->ath_spectral_lock);
+}
+
+/**
+ * target_if_is_spectral_active() - Get whether Spectral is active
+ * @pdev: Pointer to pdev object
+ *
+ * Return: True if Spectral is active, false if Spectral is not active
+ */
+static bool target_if_is_spectral_active(struct wlan_objmgr_pdev *pdev)
+{
+ struct target_if_spectral *spectral = NULL;
+ struct target_if_spectral_ops *p_sops = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+ return p_sops->is_spectral_active(spectral);
+}
+
+/**
+ * target_if_is_spectral_enabled() - Get whether Spectral is enabled
+ * @pdev: Pointer to pdev object
+ *
+ * Return: True if Spectral is enabled, false if Spectral is not enabled
+ */
+static bool target_if_is_spectral_enabled(struct wlan_objmgr_pdev *pdev)
+{
+ struct target_if_spectral *spectral = NULL;
+ struct target_if_spectral_ops *p_sops = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+ return p_sops->is_spectral_enabled(spectral);
+}
+
+/**
+ * target_if_set_debug_level() - Set debug level for Spectral
+ * @pdev: Pointer to pdev object
+ * @debug_level: Debug level
+ *
+ * Return: 0 in case of success
+ */
+static int target_if_set_debug_level(struct wlan_objmgr_pdev *pdev,
+ u_int32_t debug_level)
+{
+ spectral_debug_level = (ATH_DEBUG_SPECTRAL << debug_level);
+ return 0;
+}
+
+/**
+ * target_if_get_debug_level() - Get debug level for Spectral
+ * @pdev: Pointer to pdev object
+ *
+ * Return: Current debug level
+ */
+static u_int32_t target_if_get_debug_level(struct wlan_objmgr_pdev *pdev)
+{
+ qdf_print("target_if_get_debug_level is unimplemented\n");
+ return 0;
+}
+
+/**
+ * target_if_get_spectral_capinfo() - Get Spectral capability information
+ * @pdev: Pointer to pdev object
+ * @outdata: Buffer into which data should be copied
+ *
+ * Return: void
+ */
+static void target_if_get_spectral_capinfo(
+ struct wlan_objmgr_pdev *pdev,
+ void *outdata)
+{
+ struct target_if_spectral *spectral = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ qdf_mem_copy(outdata, &spectral->capability,
+ sizeof(struct spectral_caps));
+}
+
+/**
+ * target_if_get_spectral_diagstats() - Get Spectral diagnostic statistics
+ * @pdev: Pointer to pdev object
+ * @outdata: Buffer into which data should be copied
+ *
+ * Return: void
+ */
+static void target_if_get_spectral_diagstats(struct wlan_objmgr_pdev *pdev,
+ void *outdata)
+{
+ struct target_if_spectral *spectral = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ qdf_mem_copy(outdata, &spectral->diag_stats,
+ sizeof(struct spectral_diag_stats));
+}
+
+/**
+ * target_if_sptrl_register_tx_ops() - Register Spectral target_if Tx Ops
+ * @tx_ops: Tx Ops
+ *
+ * Return: void
+ */
+void target_if_sptrl_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops)
+{
+ tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_init =
+ target_if_pdev_spectral_init;
+ tx_ops->sptrl_tx_ops.sptrlto_pdev_spectral_deinit =
+ target_if_pdev_spectral_deinit;
+ tx_ops->sptrl_tx_ops.sptrlto_set_spectral_config =
+ target_if_set_spectral_config;
+ tx_ops->sptrl_tx_ops.sptrlto_get_spectral_config =
+ target_if_get_spectral_config;
+ tx_ops->sptrl_tx_ops.sptrlto_start_spectral_scan =
+ target_if_start_spectral_scan;
+ tx_ops->sptrl_tx_ops.sptrlto_stop_spectral_scan =
+ target_if_stop_spectral_scan;
+ tx_ops->sptrl_tx_ops.sptrlto_is_spectral_active =
+ target_if_is_spectral_active;
+ tx_ops->sptrl_tx_ops.sptrlto_is_spectral_enabled =
+ target_if_is_spectral_enabled;
+ tx_ops->sptrl_tx_ops.sptrlto_set_debug_level =
+ target_if_set_debug_level;
+ tx_ops->sptrl_tx_ops.sptrlto_get_debug_level =
+ target_if_get_debug_level;
+ tx_ops->sptrl_tx_ops.sptrlto_get_spectral_capinfo =
+ target_if_get_spectral_capinfo;
+ tx_ops->sptrl_tx_ops.sptrlto_get_spectral_diagstats =
+ target_if_get_spectral_diagstats;
+}
+EXPORT_SYMBOL(target_if_sptrl_register_tx_ops);
+
+#ifdef HOST_OFFLOAD
+extern void
+atd_spectral_msg_send(
+ struct net_device *dev,
+ SPECTRAL_SAMP_MSG * msg,
+ uint16_t msg_len);
+#endif
+
+/**
+ * target_if_spectral_send_intf_found_msg() - Send message to application layer
+ * indicating that interference has been found
+ * @pdev: Pointer to pdev
+ * @cw_int: 1 if CW interference is found, 0 if WLAN interference is found
+ * @dcs_enabled: 1 if DCS is enabled, 0 if DCS is disabled
+ *
+ * Return: None
+ */
+void target_if_spectral_send_intf_found_msg(
+ struct wlan_objmgr_pdev *pdev,
+ u_int16_t cw_int, u_int32_t dcs_enabled)
+{
+#ifdef SPECTRAL_USE_NETLINK_SOCKETS
+ SPECTRAL_SAMP_MSG *msg = NULL;
+ struct target_if_spectral_ops *p_sops = NULL;
+ struct target_if_spectral *spectral = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+ target_if_spectral_prep_skb(spectral);
+ if (spectral->spectral_skb) {
+ spectral->spectral_nlh =
+ (struct nlmsghdr *)spectral->spectral_skb->data;
+ msg = (SPECTRAL_SAMP_MSG *)NLMSG_DATA(spectral->spectral_nlh);
+ msg->int_type = cw_int ?
+ SPECTRAL_DCS_INT_CW : SPECTRAL_DCS_INT_WIFI;
+ msg->dcs_enabled = dcs_enabled;
+ msg->signature = SPECTRAL_SIGNATURE;
+ p_sops->get_mac_address(spectral, msg->macaddr);
+ target_if_spectral_bcast_msg(spectral);
+ }
+#endif
+#ifdef HOST_OFFLOAD
+ {
+ SPECTRAL_SAMP_MSG *buf = NULL;
+
+ buf = (SPECTRAL_SAMP_MSG *)OS_MALLOC(spectral->ic->ic_osdev,
+ sizeof(struct ath_spectral),
+ GFP_KERNEL);
+ buf->int_type = cw_int ? SPECTRAL_DCS_INT_CW : SPECTRAL_DCS_INT_WIFI;
+ buf->dcs_enabled = dcs_enabled;
+ buf->signature = SPECTRAL_SIGNATURE;
+ p_sops->get_mac_address(spectral, buf->macaddr);
+ atd_spectral_msg_send(spectral->ic->ic_osdev->netdev,
+ buf,
+ sizeof(SPECTRAL_SAMP_MSG));
+ OS_FREE(buf);
+ }
+#endif
+}
+EXPORT_SYMBOL(target_if_spectral_send_intf_found_msg);
+
diff --git a/target_if/spectral/target_if_spectral.h b/target_if/spectral/target_if_spectral.h
new file mode 100644
index 0000000..d916e90
--- /dev/null
+++ b/target_if/spectral/target_if_spectral.h
@@ -0,0 +1,982 @@
+/*
+ * Copyright (c) 2011,2017 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _TARGET_IF_SPECTRAL_H_
+#define _TARGET_IF_SPECTRAL_H_
+
+#include <wlan_objmgr_cmn.h>
+#include <wlan_objmgr_psoc_obj.h>
+#include <wlan_objmgr_pdev_obj.h>
+#include <qdf_lock.h>
+#include <wlan_spectral_public_structs.h>
+#include <reg_services_public_struct.h>
+
+extern int spectral_debug_level;
+
+#ifdef WIN32
+#pragma pack(push, target_if_spectral, 1)
+#define __ATTRIB_PACK
+#else
+#ifndef __ATTRIB_PACK
+#define __ATTRIB_PACK __attribute__ ((packed))
+#endif
+#endif
+
+#define spectral_log(level, args...) \
+QDF_PRINT_INFO(QDF_PRINT_IDX_SHARED, QDF_MODULE_ID_SPECTRAL, level, ## args)
+
+#define spectral_logfl(level, format, args...) \
+ spectral_log(level, FL(format), ## args)
+
+#define spectral_fatal(format, args...) \
+ spectral_logfl(QDF_TRACE_LEVEL_FATAL, format, ## args)
+#define spectral_err(format, args...) \
+ spectral_logfl(QDF_TRACE_LEVEL_ERROR, format, ## args)
+#define spectral_warn(format, args...) \
+ spectral_logfl(QDF_TRACE_LEVEL_WARN, format, ## args)
+#define spectral_info(format, args...) \
+ spectral_logfl(QDF_TRACE_LEVEL_INFO, format, ## args)
+#define spectral_debug(format, args...) \
+ spectral_logfl(QDF_TRACE_LEVEL_DEBUG, format, ## args)
+
+#define STATUS_PASS 1
+#define STATUS_FAIL 0
+#define line() \
+ qdf_print("----------------------------------------------------\n")
+#define SPECTRAL_TODO(str) \
+ qdf_print(KERN_INFO "SPECTRAL : %s (%s : %d)\n", \
+ (str), __func__, __LINE__)
+#define spectral_ops_not_registered(str) \
+ qdf_print(KERN_INFO "SPECTRAL : %s not registered\n", (str))
+#define not_yet_implemented() \
+ qdf_print("SPECTRAL : %s : %d Not yet implemented\n", \
+ __func__, __LINE__)
+
+#define SPECTRAL_HT20_NUM_BINS 56
+#define SPECTRAL_HT20_FFT_LEN 56
+#define SPECTRAL_HT20_DC_INDEX (SPECTRAL_HT20_FFT_LEN / 2)
+#define SPECTRAL_HT20_DATA_LEN 60
+#define SPECTRAL_HT20_TOTAL_DATA_LEN (SPECTRAL_HT20_DATA_LEN + 3)
+#define SPECTRAL_HT40_TOTAL_NUM_BINS 128
+#define SPECTRAL_HT40_DATA_LEN 135
+#define SPECTRAL_HT40_TOTAL_DATA_LEN (SPECTRAL_HT40_DATA_LEN + 3)
+#define SPECTRAL_HT40_FFT_LEN 128
+#define SPECTRAL_HT40_DC_INDEX (SPECTRAL_HT40_FFT_LEN / 2)
+
+/* Used for the SWAR to obtain approximate combined rssi
+ * in secondary 80Mhz segment
+ */
+#define OFFSET_CH_WIDTH_20 65
+#define OFFSET_CH_WIDTH_40 62
+#define OFFSET_CH_WIDTH_80 56
+#define OFFSET_CH_WIDTH_160 50
+
+#ifdef BIG_ENDIAN_HOST
+#define SPECTRAL_MSG_COPY_CHAR_ARRAY(destp, srcp, len) do { \
+ int j; \
+ u_int32_t *src, *dest; \
+ src = (u_int32_t *)(srcp); \
+ dest = (u_int32_t *)(destp); \
+ for (j = 0; j < roundup((len), sizeof(u_int32_t)) / 4; j++) { \
+ *(dest + j) = qdf_le32_to_cpu(*(src + j)); \
+ } \
+ } while (0)
+#else
+#define SPECTRAL_MSG_COPY_CHAR_ARRAY(destp, srcp, len) \
+ OS_MEMCPY((destp), (srcp), (len));
+#endif
+
+/* 5 categories x (lower + upper) bands */
+#define MAX_INTERF 10
+#define ATH_HOST_MAX_ANTENNA 3
+/* Mask for time stamp from descriptor */
+#define SPECTRAL_TSMASK 0xFFFFFFFF
+#define SPECTRAL_SIGNATURE 0xdeadbeef
+#define MAX_SPECTRAL_PAYLOAD 1500
+#ifndef NETLINK_ATHEROS
+#define NETLINK_ATHEROS (NETLINK_GENERIC + 1)
+#endif
+
+/* START of spectral GEN II HW specific details */
+#define SPECTRAL_PHYERR_SIGNATURE_GEN2 0xbb
+#define TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2 0xF9
+#define TLV_TAG_ADC_REPORT_GEN2 0xFA
+#define TLV_TAG_SEARCH_FFT_REPORT_GEN2 0xFB
+
+/**
+ * struct spectral_search_fft_info_gen2 - spectral search fft report for gen2
+ * @relpwr_db: Total bin power in db
+ * @num_str_bins_ib: Number of strong bins
+ * @base_pwr: Base power
+ * @total_gain_info: Total gain
+ * @fft_chn_idx: FFT chain on which report is originated
+ * @avgpwr_db: Average power in db
+ * @peak_mag: Peak power seen in the bins
+ * @peak_inx: Index of bin holding peak power
+ */
+typedef struct spectral_search_fft_info_gen2 {
+ uint32_t relpwr_db;
+ uint32_t num_str_bins_ib;
+ uint32_t base_pwr;
+ uint32_t total_gain_info;
+ uint32_t fft_chn_idx;
+ uint32_t avgpwr_db;
+ uint32_t peak_mag;
+ int16_t peak_inx;
+} SPECTRAL_SEARCH_FFT_INFO_GEN2;
+
+/* XXX Check if we should be handling the endinness difference in some
+ * other way opaque to the host
+ */
+#ifdef BIG_ENDIAN_HOST
+
+/**
+ * struct spectral_phyerr_tlv_gen2 - phyerr tlv info for big endian host
+ * @signature: signature
+ * @tag: tag
+ * @length: length
+ */
+typedef struct spectral_phyerr_tlv_gen2 {
+ u_int8_t signature;
+ u_int8_t tag;
+ u_int16_t length;
+} __ATTRIB_PACK SPECTRAL_PHYERR_TLV_GEN2;
+
+#else
+
+/**
+ * struct spectral_phyerr_tlv_gen2 - phyerr tlv info for little endian host
+ * @length: length
+ * @tag: tag
+ * @signature: signature
+ */
+typedef struct spectral_phyerr_tlv_gen2 {
+ u_int16_t length;
+ u_int8_t tag;
+ u_int8_t signature;
+} __ATTRIB_PACK SPECTRAL_PHYERR_TLV_GEN2;
+
+#endif /* BIG_ENDIAN_HOST */
+
+/**
+ * struct spectral_phyerr_hdr_gen2 - phyerr header for gen2 HW
+ * @hdr_a: Header[0:31]
+ * @hdr_b: Header[32:63]
+ */
+typedef struct spectral_phyerr_hdr_gen2 {
+ u_int32_t hdr_a;
+ u_int32_t hdr_b;
+} SPECTRAL_PHYERR_HDR_GEN2;
+
+/* Segment ID information for 80+80.
+ *
+ * If the HW micro-architecture specification extends this DWORD for other
+ * purposes, then redefine+rename accordingly. For now, the specification
+ * mentions only segment ID (though this doesn't require an entire DWORD)
+ * without mention of any generic terminology for the DWORD, or any reservation.
+ * We use nomenclature accordingly.
+ */
+typedef u_int32_t SPECTRAL_SEGID_INFO;
+
+/**
+ * struct spectral_phyerr_fft_gen2 - fft info in phyerr event
+ * @buf: fft report
+ */
+typedef struct spectral_phyerr_fft_gen2 {
+ u_int8_t buf[0];
+} SPECTRAL_PHYERR_FFT_GEN2;
+/* END of spectral GEN II HW specific details */
+
+/* START of spectral GEN III HW specific details */
+
+#define get_bitfield(value, size, pos) \
+ (((value) >> (pos)) & ((1 << (size)) - 1))
+#define unsigned_to_signed(value, width) \
+ (((value) >= (1 << ((width) - 1))) ? \
+ (value - (1 << (width))) : (value))
+
+#define SPECTRAL_PHYERR_SIGNATURE_GEN3 (0xFA)
+#define TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3 (0x02)
+#define TLV_TAG_SEARCH_FFT_REPORT_GEN3 (0x03)
+#define SPECTRAL_PHYERR_TLVSIZE_GEN3 (4)
+
+#define PHYERR_HDR_SIG_POS \
+ (offsetof(struct spectral_phyerr_fft_report_gen3, fft_hdr_sig))
+#define PHYERR_HDR_TAG_POS \
+ (offsetof(struct spectral_phyerr_fft_report_gen3, fft_hdr_tag))
+#define SPECTRAL_FFT_BINS_POS \
+ (offsetof(struct spectral_phyerr_fft_report_gen3, buf))
+
+/**
+ * struct phyerr_info - spectral search fft report for gen3
+ * @data: handle to phyerror buffer
+ * @datalen: length of phyerror bufer
+ * @p_rfqual: rf quality matrices
+ * @p_chaninfo: pointer to chaninfo
+ * @tsf64: 64 bit TSF
+ * @acs_stats: acs stats
+ */
+struct phyerr_info {
+ u_int8_t *data;
+ u_int32_t datalen;
+ struct target_if_spectral_rfqual_info *p_rfqual;
+ struct target_if_spectral_chan_info *p_chaninfo;
+ u_int64_t tsf64;
+ struct target_if_spectral_acs_stats *acs_stats;
+};
+
+/**
+ * struct spectral_search_fft_info_gen3 - spectral search fft report for gen3
+ * @timestamp: Timestamp at which fft report was generated
+ * @fft_detector_id: Which radio generated this report
+ * @fft_num: The FFT count number. Set to 0 for short FFT.
+ * @fft_radar_check: NA for spectral
+ * @fft_peak_sidx: Index of bin with maximum power
+ * @fft_chn_idx: Rx chain index
+ * @fft_base_pwr_db: Base power in dB
+ * @fft_total_gain_db: Total gain in dB
+ * @fft_num_str_bins_ib: Number of strong bins in the report
+ * @fft_peak_mag: Peak magnitude
+ * @fft_avgpwr_db: Average power in dB
+ * @fft_relpwr_db: Relative power in dB
+ */
+struct spectral_search_fft_info_gen3 {
+ uint32_t timestamp;
+ uint32_t fft_detector_id;
+ uint32_t fft_num;
+ uint32_t fft_radar_check;
+ int32_t fft_peak_sidx;
+ uint32_t fft_chn_idx;
+ uint32_t fft_base_pwr_db;
+ uint32_t fft_total_gain_db;
+ uint32_t fft_num_str_bins_ib;
+ int32_t fft_peak_mag;
+ uint32_t fft_avgpwr_db;
+ uint32_t fft_relpwr_db;
+};
+
+/**
+ * struct spectral_phyerr_sfftreport_gen3 - fft info in phyerr event
+ * @fft_timestamp: Timestamp at which fft report was generated
+ * @fft_hdr_sig: signature
+ * @fft_hdr_tag: tag
+ * @fft_hdr_length: length
+ * @hdr_a: Header[0:31]
+ * @hdr_b: Header[32:63]
+ * @hdr_c: Header[64:95]
+ * @resv: Header[96:127]
+ * @buf: fft bins
+ */
+struct spectral_phyerr_fft_report_gen3 {
+ u_int32_t fft_timestamp;
+#ifdef BIG_ENDIAN_HOST
+ u_int8_t fft_hdr_sig;
+ u_int8_t fft_hdr_tag;
+ u_int16_t fft_hdr_length;
+#else
+ u_int16_t fft_hdr_length;
+ u_int8_t fft_hdr_tag;
+ u_int8_t fft_hdr_sig;
+#endif /* BIG_ENDIAN_HOST */
+ u_int32_t hdr_a;
+ u_int32_t hdr_b;
+ u_int32_t hdr_c;
+ u_int32_t resv;
+ u_int8_t buf[0];
+} __ATTRIB_PACK;
+
+/* END of spectral GEN III HW specific details */
+
+typedef signed char pwr_dbm;
+
+/**
+ * enum spectral_gen - spectral hw generation
+ * @SPECTRAL_GEN1 : spectral hw gen 1
+ * @SPECTRAL_GEN2 : spectral hw gen 2
+ * @SPECTRAL_GEN3 : spectral hw gen 3
+ */
+enum spectral_gen {
+ SPECTRAL_GEN1,
+ SPECTRAL_GEN2,
+ SPECTRAL_GEN3,
+};
+
+#if ATH_PERF_PWR_OFFLOAD
+/**
+ * enum ol_spectral_info_spec - Enumerations for specifying which spectral
+ * information (among parameters and states)
+ * is desired.
+ * @OL_SPECTRAL_INFO_SPEC_ACTIVE: Indicated whether spectral is active
+ * @OL_SPECTRAL_INFO_SPEC_ENABLED: Indicated whether spectral is enabled
+ * @OL_SPECTRAL_INFO_SPEC_PARAMS: Config params
+ */
+enum ol_spectral_info_spec {
+ OL_SPECTRAL_INFO_SPEC_ACTIVE,
+ OL_SPECTRAL_INFO_SPEC_ENABLED,
+ OL_SPECTRAL_INFO_SPEC_PARAMS,
+};
+#endif /* ATH_PERF_PWR_OFFLOAD */
+
+/* forward declaration */
+struct target_if_spectral;
+
+/**
+ * struct target_if_spectral_chan_info - Channel information
+ * @center_freq1: center frequency 1 in MHz
+ * @center_freq2: center frequency 2 in MHz -valid only for
+ * 11ACVHT 80PLUS80 mode
+ * @chan_width: channel width in MHz
+ */
+struct target_if_spectral_chan_info {
+ u_int16_t center_freq1;
+ u_int16_t center_freq2;
+ u_int8_t chan_width;
+};
+
+/**
+ * struct target_if_spectral_acs_stats - EACS stats from spectral samples
+ * @nfc_ctl_rssi: Control chan rssi
+ * @nfc_ext_rssi: Extension chan rssi
+ * @ctrl_nf: Control chan Noise Floor
+ * @ext_nf: Extension chan Noise Floor
+ */
+struct target_if_spectral_acs_stats {
+ int8_t nfc_ctl_rssi;
+ int8_t nfc_ext_rssi;
+ int8_t ctrl_nf;
+ int8_t ext_nf;
+};
+
+/**
+ * struct target_if_spectral_perchain_rssi_info - per chain rssi info
+ * @rssi_pri20: Rssi of primary 20 Mhz
+ * @rssi_sec20: Rssi of secondary 20 Mhz
+ * @rssi_sec40: Rssi of secondary 40 Mhz
+ * @rssi_sec80: Rssi of secondary 80 Mhz
+ */
+struct target_if_spectral_perchain_rssi_info {
+ int8_t rssi_pri20;
+ int8_t rssi_sec20;
+ int8_t rssi_sec40;
+ int8_t rssi_sec80;
+};
+
+/**
+ * struct target_if_spectral_rfqual_info - RF measurement information
+ * @rssi_comb: RSSI Information
+ * @pc_rssi_info: XXX : For now, we know we are getting information
+ * for only 4 chains at max. For future extensions
+ * use a define
+ * @noise_floor: Noise floor information
+ */
+struct target_if_spectral_rfqual_info {
+ int8_t rssi_comb;
+ struct target_if_spectral_perchain_rssi_info pc_rssi_info[4];
+ int16_t noise_floor[4];
+};
+
+#define GET_TIF_SPECTRAL_OPS(spectral) \
+ ((struct target_if_spectral_ops *)(&((spectral)->spectral_ops)))
+
+/**
+ * struct target_if_spectral_ops - spectral low level ops table
+ * @get_tsf64: Get 64 bit TSF value
+ * @get_capability: Get capability info
+ * @set_rxfilter: Set rx filter
+ * @get_rxfilter: Get rx filter
+ * @is_spectral_active: Check whether icm is active
+ * @is_spectral_enabled: Check whether spectral is enabled
+ * @start_spectral_scan: Start spectral scan
+ * @stop_spectral_scan: Stop spectral scan
+ * @get_extension_channel: Get extension channel
+ * @get_ctl_noisefloor: Get control noise floor
+ * @get_ext_noisefloor: Get extension noise floor
+ * @configure_spectral: Set spectral configurations
+ * @get_spectral_config: Get spectral configurations
+ * @get_ent_spectral_mask: Get spectral mask
+ * @get_mac_address: Get mac address
+ * @get_current_channel: Get current channel
+ * @reset_hw: Reset HW
+ * @get_chain_noise_floor: Get Channel noise floor
+ * @spectral_process_phyerr: Process phyerr event
+ */
+struct target_if_spectral_ops {
+ u_int64_t (*get_tsf64)(void *arg);
+ u_int32_t (*get_capability)(void *arg, SPECTRAL_CAPABILITY_TYPE type);
+ u_int32_t (*set_rxfilter)(void *arg, int rxfilter);
+ u_int32_t (*get_rxfilter)(void *arg);
+ u_int32_t (*is_spectral_active)(void *arg);
+ u_int32_t (*is_spectral_enabled)(void *arg);
+ u_int32_t (*start_spectral_scan)(void *arg);
+ u_int32_t (*stop_spectral_scan)(void *arg);
+ u_int32_t (*get_extension_channel)(void *arg);
+ int8_t (*get_ctl_noisefloor)(void *arg);
+ int8_t (*get_ext_noisefloor)(void *arg);
+ u_int32_t (*configure_spectral)(
+ void *arg,
+ struct spectral_config *params);
+ u_int32_t (*get_spectral_config)(
+ void *arg,
+ struct spectral_config *params);
+ u_int32_t (*get_ent_spectral_mask)(void *arg);
+ u_int32_t (*get_mac_address)(void *arg, char *addr);
+ u_int32_t (*get_current_channel)(void *arg);
+ u_int32_t (*reset_hw)(void *arg);
+ u_int32_t (*get_chain_noise_floor)(void *arg, int16_t *nf_buf);
+ int (*spectral_process_phyerr)(struct target_if_spectral *spectral,
+ u_int8_t *data, u_int32_t datalen,
+ struct target_if_spectral_rfqual_info *p_rfqual,
+ struct target_if_spectral_chan_info *p_chaninfo,
+ u_int64_t tsf64,
+ struct target_if_spectral_acs_stats *acs_stats);
+};
+
+/**
+ * struct target_if_spectral_stats - spectral stats info
+ * @num_spectral_detects: Total num. of spectral detects
+ * @total_phy_errors: Total number of phyerrors
+ * @owl_phy_errors: Indicated phyerrors in old gen1 chipsets
+ * @pri_phy_errors: Phyerrors in primary channel
+ * @ext_phy_errors: Phyerrors in secondary channel
+ * @dc_phy_errors: Phyerrors due to dc
+ * @early_ext_phy_errors: Early secondary channel phyerrors
+ * @bwinfo_errors: Bandwidth info errors
+ * @datalen_discards: Invalid data length errors, seen in gen1 chipsets
+ * @rssi_discards bw: Indicates reports dropped due to RSSI threshold
+ * @last_reset_tstamp: Last reset time stamp
+ */
+struct target_if_spectral_stats {
+ u_int32_t num_spectral_detects;
+ u_int32_t total_phy_errors;
+ u_int32_t owl_phy_errors;
+ u_int32_t pri_phy_errors;
+ u_int32_t ext_phy_errors;
+ u_int32_t dc_phy_errors;
+ u_int32_t early_ext_phy_errors;
+ u_int32_t bwinfo_errors;
+ u_int32_t datalen_discards;
+ u_int32_t rssi_discards;
+ u_int64_t last_reset_tstamp;
+};
+
+/**
+ * struct target_if_spectral_event - spectral event structure
+ * @se_ts: Original 15 bit recv timestamp
+ * @se_full_ts: 64-bit full timestamp from interrupt time
+ * @se_rssi: Rssi of spectral event
+ * @se_bwinfo: Rssi of spectral event
+ * @se_dur: Duration of spectral pulse
+ * @se_chanindex: Channel of event
+ * @se_list: List of spectral events
+ */
+struct target_if_spectral_event {
+ u_int32_t se_ts;
+ u_int64_t se_full_ts;
+ u_int8_t se_rssi;
+ u_int8_t se_bwinfo;
+ u_int8_t se_dur;
+ u_int8_t se_chanindex;
+
+ STAILQ_ENTRY(spectral_event) se_list;
+};
+
+/**
+ * struct target_if_chain_noise_pwr_info - Noise power info for each channel
+ * @rptcount: Count of reports in pwr array
+ * @un_cal_nf: Uncalibrated noise floor
+ * @factory_cal_nf: Noise floor as calibrated at the factory for module
+ * @median_pwr: Median power (median of pwr array)
+ * @pwr: Power reports
+ */
+struct target_if_chain_noise_pwr_info {
+ int rptcount;
+ pwr_dbm un_cal_nf;
+ pwr_dbm factory_cal_nf;
+ pwr_dbm median_pwr;
+ pwr_dbm pwr[];
+} __ATTRIB_PACK;
+
+/**
+ * struct target_if_spectral_chan_stats - Channel information
+ * @cycle_count: Cycle count
+ * @channel_load: Channel load
+ * @per: Period
+ * @noisefloor: Noise floor
+ * @comp_usablity: Computed usability
+ * @maxregpower: Maximum allowed regulatary power
+ * @comp_usablity_sec80: Computed usability of secondary 80 Mhz
+ * @maxregpower_sec80: Max regulatory power in secondary 80 Mhz
+ */
+struct target_if_spectral_chan_stats {
+ int cycle_count;
+ int channel_load;
+ int per;
+ int noisefloor;
+ u_int16_t comp_usablity;
+ int8_t maxregpower;
+ u_int16_t comp_usablity_sec80;
+ int8_t maxregpower_sec80;
+};
+
+#if ATH_PERF_PWR_OFFLOAD
+/* Locking operations
+ * We have a separate set of definitions for offload to accommodate
+ * offload specific changes in the future.
+ */
+#define OL_SPECTRAL_LOCK_INIT(_lock) qdf_spinlock_create((_lock))
+#define OL_SPECTRAL_LOCK_DESTROY(_lock) qdf_spinlock_destroy((_lock))
+#define OL_SPECTRAL_LOCK(_lock) qdf_spin_lock((_lock))
+#define OL_SPECTRAL_UNLOCK(_lock) qdf_spin_unlock((_lock))
+
+/**
+ * struct target_if_spectral_cache - Cache used to minimize WMI operations
+ * in offload architecture
+ * @osc_spectral_enabled: Whether Spectral is enabled
+ * @osc_spectral_active: Whether spectral is active
+ * XXX: Ideally, we should NOT cache this
+ * since the hardware can self clear the bit,
+ * the firmware can possibly stop spectral due to
+ * intermittent off-channel activity, etc
+ * A WMI read command should be introduced to handle
+ * this This will be discussed.
+ * @osc_params: Spectral parameters
+ * @osc_is_valid: Whether the cache is valid
+ */
+struct target_if_spectral_cache {
+ u_int8_t osc_spectral_enabled;
+ u_int8_t osc_spectral_active;
+ struct spectral_config osc_params;
+ u_int8_t osc_is_valid;
+};
+
+/**
+ * struct target_if_spectral_param_state_info - Structure used to represent and
+ * manage spectral information
+ * (parameters and states)
+ * @osps_lock: Lock to synchronize accesses to information
+ * @osps_cache: Cacheable' information
+ */
+struct target_if_spectral_param_state_info {
+ qdf_spinlock_t osps_lock;
+ struct target_if_spectral_cache osps_cache;
+ /* XXX - Non-cacheable information goes here, in the future */
+};
+#endif /* ATH_PERF_PWR_OFFLOAD */
+
+/**
+ * struct target_if_spectral - main spectral structure
+ * @pdev: Pointer to pdev
+ * @spectral_ops: Target if internal Spectral low level operations table
+ * @capability: Spectral capabilities structure
+ * @ath_spectral_lock: Lock used for internal Spectral operations
+ * @spectral_curchan_radindex: Current channel spectral index
+ * @spectral_extchan_radindex: Extension channel spectral index
+ * @spectraldomain: Current Spectral domain
+ * @spectral_proc_phyerr: Flags to process for PHY errors
+ * @spectral_defaultparams: Default PHY params per Spectral stat
+ * @ath_spectral_stats: Spectral related stats
+ * @events: Events structure
+ * @sc_spectral_ext_chan_ok: Can spectral be detected on the extension channel?
+ * @sc_spectral_combined_rssi_ok: Can use combined spectral RSSI?
+ * @sc_spectral_20_40_mode: Is AP in 20-40 mode?
+ * @sc_spectral_noise_pwr_cal: Noise power cal required?
+ * @sc_spectral_non_edma: Is the spectral capable device Non-EDMA?
+ * @upper_is_control: Upper segment is primary
+ * @upper_is_extension: Upper segment is secondary
+ * @lower_is_control: Lower segment is primary
+ * @lower_is_extension: Lower segment is secondary
+ * @sc_spectraltest_ieeechan: IEEE channel number to return to after a spectral
+ * mute test
+ * @spectral_numbins: Number of bins
+ * @spectral_fft_len: FFT length
+ * @spectral_data_len: Total phyerror report length
+ * @lb_edge_extrabins: Number of extra bins on left band edge
+ * @rb_edge_extrabins: Number of extra bins on right band edge
+ * @spectral_max_index_offset: Max FFT index offset (20 MHz mode)
+ * @spectral_upper_max_index_offset: Upper max FFT index offset (20/40 MHz mode)
+ * @spectral_lower_max_index_offset: Lower max FFT index offset (20/40 MHz mode)
+ * @spectral_dc_index: At which index DC is present
+ * @send_single_packet: Deprecated
+ * @spectral_sent_msg: Indicates whether we send report to upper layers
+ * @params: Spectral parameters
+ * @last_capture_time: Indicates timestamp of previouse report
+ * @num_spectral_data: Number of Spectral samples received in current session
+ * @total_spectral_data: Total number of Spectral samples received
+ * @max_rssi: Maximum RSSI
+ * @detects_control_channel: NA
+ * @detects_extension_channel: NA
+ * @detects_below_dc: NA
+ * @detects_above_dc: NA
+ * @sc_scanning: Indicates active wifi scan
+ * @sc_spectral_scan: Indicates active specral scan
+ * @sc_spectral_full_scan: Deprecated
+ * @scan_start_tstamp: Deprecated
+ * @last_tstamp: Deprecated
+ * @first_tstamp: Deprecated
+ * @spectral_samp_count: Deprecated
+ * @sc_spectral_samp_count: Deprecated
+ * @noise_pwr_reports_reqd: Number of noise power reports required
+ * @noise_pwr_reports_recv: Number of noise power reports received
+ * @noise_pwr_reports_lock: Lock used for Noise power report processing
+ * @noise_pwr_chain_ctl: Noise power report - control channel
+ * @noise_pwr_chain_ext: Noise power report - extension channel
+ * @chaninfo: Channel statistics
+ * @tsf64: Latest TSF Value
+ * @ol_info: Offload architecture Spectral parameter cache information
+ * @ch_width: Indicates Channel Width 20/40/80/160 MHz with values 0, 1, 2, 3
+ * respectively
+ * @diag_stats: Diagnostic statistics
+ * @is_160_format: Indicates whether information provided by HW is in altered
+ * format for 802.11ac 160/80+80 MHz support (QCA9984 onwards)
+ * @is_lb_edge_extrabins_format: Indicates whether information provided by
+ * HW has 4 extra bins, at left band edge, for report mode 2
+ * @is_rb_edge_extrabins_format: Indicates whether information provided
+ * by HW has 4 extra bins, at right band edge, for report mode 2
+ * @is_sec80_rssi_war_required: Indicates whether the software workaround is
+ * required to obtain approximate combined RSSI for secondary 80Mhz segment
+ * @simctx: Spectral Simulation context
+ * @spectral_gen: Spectral hardware generation
+ * @hdr_sig_exp: Expected signature in PHYERR TLV header, for the given hardware
+ * generation
+ * @tag_sscan_summary_exp: Expected Spectral Scan Summary tag in PHYERR TLV
+ * header, for the given hardware generation
+ * @tag_sscan_fft_exp: Expected Spectral Scan FFT report tag in PHYERR TLV
+ * header, for the given hardware generation
+ * @tlvhdr_size: Expected PHYERR TLV header size, for the given hardware
+ * generation
+ */
+struct target_if_spectral {
+ struct wlan_objmgr_pdev *pdev_obj;
+ struct target_if_spectral_ops spectral_ops;
+ struct spectral_caps capability;
+ qdf_spinlock_t ath_spectral_lock;
+ int16_t spectral_curchan_radindex;
+ int16_t spectral_extchan_radindex;
+ u_int32_t spectraldomain;
+ u_int32_t spectral_proc_phyerr;
+ struct spectral_config spectral_defaultparams;
+ struct target_if_spectral_stats ath_spectral_stats;
+ struct target_if_spectral_event *events;
+ unsigned int sc_spectral_ext_chan_ok:1,
+ sc_spectral_combined_rssi_ok:1,
+ sc_spectral_20_40_mode:1,
+ sc_spectral_noise_pwr_cal:1,
+ sc_spectral_non_edma:1;
+ int upper_is_control;
+ int upper_is_extension;
+ int lower_is_control;
+ int lower_is_extension;
+ u_int8_t sc_spectraltest_ieeechan;
+ struct sock *spectral_sock;
+ struct sk_buff *spectral_skb;
+ struct nlmsghdr *spectral_nlh;
+ u_int32_t spectral_pid;
+
+ STAILQ_HEAD(, target_if_spectral_skb_event) spectral_skbq;
+ qdf_spinlock_t spectral_skbqlock;
+ int spectral_numbins;
+ int spectral_fft_len;
+ int spectral_data_len;
+
+ /* For 11ac chipsets prior to AR900B version 2.0, a max of 512 bins are
+ * delivered. However, there can be additional bins reported for
+ * AR900B version 2.0 and QCA9984 as described next:
+ *
+ * AR900B version 2.0: An additional tone is processed on the right
+ * hand side in order to facilitate detection of radar pulses out to
+ * the extreme band-edge of the channel frequency. Since the HW design
+ * processes four tones at a time, this requires one additional Dword
+ * to be added to the search FFT report.
+ *
+ * QCA9984: When spectral_scan_rpt_mode = 2, i.e 2-dword summary +
+ * 1x-oversampled bins (in-band) per FFT, then 8 more bins
+ * (4 more on left side and 4 more on right side)are added.
+ */
+
+ int lb_edge_extrabins;
+ int rb_edge_extrabins;
+ int spectral_max_index_offset;
+ int spectral_upper_max_index_offset;
+ int spectral_lower_max_index_offset;
+ int spectral_dc_index;
+ int send_single_packet;
+ int spectral_sent_msg;
+ int classify_scan;
+ os_timer_t classify_timer;
+ struct spectral_config params;
+ struct spectral_classifier_params classifier_params;
+ int last_capture_time;
+ int num_spectral_data;
+ int total_spectral_data;
+ int max_rssi;
+ int detects_control_channel;
+ int detects_extension_channel;
+ int detects_below_dc;
+ int detects_above_dc;
+ int sc_scanning;
+ int sc_spectral_scan;
+ int sc_spectral_full_scan;
+ u_int64_t scan_start_tstamp;
+ u_int32_t last_tstamp;
+ u_int32_t first_tstamp;
+ u_int32_t spectral_samp_count;
+ u_int32_t sc_spectral_samp_count;
+ int noise_pwr_reports_reqd;
+ int noise_pwr_reports_recv;
+ qdf_spinlock_t noise_pwr_reports_lock;
+ struct target_if_chain_noise_pwr_info
+ *noise_pwr_chain_ctl[ATH_HOST_MAX_ANTENNA];
+ struct target_if_chain_noise_pwr_info
+ *noise_pwr_chain_ext[ATH_HOST_MAX_ANTENNA];
+ u_int64_t tsf64;
+#if ATH_PERF_PWR_OFFLOAD
+ struct target_if_spectral_param_state_info ol_info;
+#endif
+ u_int32_t ch_width;
+ struct spectral_diag_stats diag_stats;
+ bool is_160_format;
+ bool is_lb_edge_extrabins_format;
+ bool is_rb_edge_extrabins_format;
+ bool is_sec80_rssi_war_required;
+#if QCA_SUPPORT_SPECTRAL_SIMULATION
+ void *simctx;
+#endif
+ enum spectral_gen spectral_gen;
+ u_int8_t hdr_sig_exp;
+ u_int8_t tag_sscan_summary_exp;
+ u_int8_t tag_sscan_fft_exp;
+ u_int8_t tlvhdr_size;
+};
+
+/**
+ * struct target_if_spectral_skb_event - Used to broadcast FFT report to
+ * applications
+ * @sp_skb: Pointer to skb
+ * @sp_nlh: Pointer to nl message header
+ * @spectral_skb_list: Linked list to manipulate the reports
+ */
+struct target_if_spectral_skb_event {
+ struct sk_buff *sp_skb;
+ struct nlmsghdr *sp_nlh;
+
+ STAILQ_ENTRY(target_if_spectral_skb_event) spectral_skb_list;
+};
+
+/* TODO:COMMENTS */
+struct target_if_samp_msg_params {
+ int8_t rssi;
+ int8_t rssi_sec80;
+ int8_t lower_rssi;
+ int8_t upper_rssi;
+ int8_t chain_ctl_rssi[ATH_HOST_MAX_ANTENNA];
+ int8_t chain_ext_rssi[ATH_HOST_MAX_ANTENNA];
+ uint16_t bwinfo;
+ uint16_t datalen;
+ uint16_t datalen_sec80;
+ uint32_t tstamp;
+ uint32_t last_tstamp;
+ uint16_t max_mag;
+ uint16_t max_mag_sec80;
+ uint16_t max_index;
+ uint16_t max_index_sec80;
+ uint8_t max_exp;
+ int peak;
+ int pwr_count;
+ int pwr_count_sec80;
+ int8_t nb_lower;
+ int8_t nb_upper;
+ uint16_t max_lower_index;
+ uint16_t max_upper_index;
+ u_int8_t *bin_pwr_data;
+ u_int8_t *bin_pwr_data_sec80;
+ u_int16_t freq;
+ u_int16_t vhtop_ch_freq_seg1;
+ u_int16_t vhtop_ch_freq_seg2;
+ u_int16_t freq_loading;
+ int16_t noise_floor;
+ int16_t noise_floor_sec80;
+ struct INTERF_SRC_RSP interf_list;
+ SPECTRAL_CLASSIFIER_PARAMS classifier_params;
+ struct ath_softc *sc;
+};
+
+/* NETLINK related declarations */
+#ifdef SPECTRAL_USE_NETLINK_SOCKETS
+#if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE)
+ void spectral_nl_data_ready(struct sock *sk, int len);
+#else
+ void spectral_nl_data_ready(struct sk_buff *skb);
+#endif /* VERSION CHECK */
+#endif /* SPECTRAL_USE_NETLINK_SOCKETS defined */
+
+void target_if_sptrl_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops);
+extern struct net init_net;
+int target_if_spectral_init_netlink(struct target_if_spectral *spectral);
+int target_if_spectral_destroy_netlink(struct target_if_spectral *spectral);
+void target_if_spectral_unicast_msg(struct target_if_spectral *spectral);
+void target_if_spectral_bcast_msg(struct target_if_spectral *spectral);
+void target_if_spectral_prep_skb(struct target_if_spectral *spectral);
+void target_if_spectral_skb_dequeue(unsigned long data);
+void target_if_spectral_create_samp_msg(
+ struct target_if_spectral *spectral,
+ struct target_if_samp_msg_params *params);
+int spectral_process_phyerr_gen3(
+ struct target_if_spectral *spectral,
+ u_int8_t *data,
+ u_int32_t datalen, struct target_if_spectral_rfqual_info *p_rfqual,
+ struct target_if_spectral_chan_info *p_chaninfo,
+ u_int64_t tsf64,
+ struct target_if_spectral_acs_stats *acs_stats);
+int spectral_process_phyerr_gen2(
+ struct target_if_spectral *spectral,
+ u_int8_t *data,
+ u_int32_t datalen, struct target_if_spectral_rfqual_info *p_rfqual,
+ struct target_if_spectral_chan_info *p_chaninfo,
+ u_int64_t tsf64,
+ struct target_if_spectral_acs_stats *acs_stats);
+void target_if_spectral_send_intf_found_msg(
+ struct wlan_objmgr_pdev *pdev,
+ u_int16_t cw_int, u_int32_t dcs_enabled);
+void target_if_stop_spectral_scan(struct wlan_objmgr_pdev *pdev);
+struct wlan_objmgr_vdev *target_if_spectral_get_vdev(
+ struct target_if_spectral *spectral);
+
+int spectral_dump_header_gen2(SPECTRAL_PHYERR_HDR_GEN2 *phdr);
+int8_t get_combined_rssi_sec80_segment_gen2(
+ struct target_if_spectral *spectral,
+ SPECTRAL_SEARCH_FFT_INFO_GEN2 *p_sfft_sec80);
+int spectral_dump_tlv_gen2(SPECTRAL_PHYERR_TLV_GEN2 *ptlv, bool is_160_format);
+int spectral_dump_phyerr_data_gen2(
+ u_int8_t *data,
+ u_int32_t datalen,
+ bool is_160_format);
+int spectral_dump_fft_report_gen3(
+ struct spectral_phyerr_fft_report_gen3 *p_fft_report,
+ struct spectral_search_fft_info_gen3 *p_sfft);
+
+void target_if_dbg_print_SAMP_msg(SPECTRAL_SAMP_MSG *pmsg);
+
+/* START of spectral GEN III HW specific function declarations */
+/* [FIXME] fix the declaration */
+int process_search_fft_report_gen3(
+ struct spectral_phyerr_fft_report_gen3 *p_fft_report,
+ struct spectral_search_fft_info_gen3 *p_fft_info);
+/* END of spectral GEN III HW specific function declarations */
+
+/**
+ * target_if_send_phydata() - Send Spectral PHY data over netlink
+ * @pdev: Pointer to pdev
+ * @sock: Netlink socket to use
+ * @nbuf: Network buffer containing PHY data to send
+ *
+ * Return: 0 on success, negative value on failure
+ */
+static inline uint32_t target_if_send_phydata(
+ struct wlan_objmgr_pdev *pdev,
+ struct sock *sock, qdf_nbuf_t nbuf)
+{
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+ return psoc->soc_cb.rx_ops.sptrl_rx_ops.sptrlro_send_phydata(pdev,
+ sock, nbuf);
+}
+
+/**
+ * get_target_if_spectral_handle_from_pdev() - Get handle to target_if internal
+ * Spectral data
+ * @pdev: Pointer to pdev
+ *
+ * Return: Handle to target_if internal Spectral data on success, NULL on
+ * failure
+ */
+static inline
+struct target_if_spectral *get_target_if_spectral_handle_from_pdev(
+ struct wlan_objmgr_pdev *pdev)
+{
+ struct target_if_spectral *spectral = NULL;
+ struct wlan_objmgr_psoc *psoc = NULL;
+
+ psoc = wlan_pdev_get_psoc(pdev);
+
+ spectral = (struct target_if_spectral *)
+ psoc->soc_cb.rx_ops.sptrl_rx_ops.sptrlro_get_target_handle(
+ pdev);
+ return spectral;
+}
+
+/**
+ * target_if_spectral_set_rxchainmask() - Set Spectral Rx chainmask
+ * @pdev: Pointer to pdev
+ * @spectral_rx_chainmask: Spectral Rx chainmask
+ *
+ * Return: None
+ */
+static inline
+void target_if_spectral_set_rxchainmask(struct wlan_objmgr_pdev *pdev,
+ u_int8_t spectral_rx_chainmask)
+{
+ struct target_if_spectral *spectral = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ spectral->params.ss_chn_mask = spectral_rx_chainmask;
+}
+
+/**
+ * target_if_spectral_process_phyerr() - Process Spectral PHY error
+ * @pdev: Pointer to pdev
+ * @data: PHY error data received from FW
+ * @datalen: Length of data
+ * @p_rfqual: Pointer to RF Quality information
+ * @p_chaninfo: Pointer to channel information
+ * @tsf: TSF time instance at which the Spectral sample was received
+ * @acs_stats: ACS stats
+ *
+ * Process Spectral PHY error by extracting necessary information from the data
+ * sent by FW, and send the extracted information to application layer.
+ *
+ * Return: None
+ */
+static inline
+void target_if_spectral_process_phyerr(
+ struct wlan_objmgr_pdev *pdev,
+ u_int8_t *data, u_int32_t datalen,
+ struct target_if_spectral_rfqual_info *p_rfqual,
+ struct target_if_spectral_chan_info *p_chaninfo,
+ u_int64_t tsf64,
+ struct target_if_spectral_acs_stats *acs_stats)
+{
+ struct target_if_spectral *spectral = NULL;
+ struct target_if_spectral_ops *p_sops = NULL;
+
+ spectral = get_target_if_spectral_handle_from_pdev(pdev);
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+ p_sops->spectral_process_phyerr(spectral, data, datalen,
+ p_rfqual, p_chaninfo,
+ tsf64, acs_stats);
+}
+
+#ifdef WIN32
+#pragma pack(pop, target_if_spectral)
+#endif
+#ifdef __ATTRIB_PACK
+#undef __ATTRIB_PACK
+#endif
+
+#endif /* _TARGET_IF_SPECTRAL_H_ */
diff --git a/target_if/spectral/target_if_spectral_netlink.c b/target_if/spectral/target_if_spectral_netlink.c
new file mode 100644
index 0000000..458e2ce
--- /dev/null
+++ b/target_if/spectral/target_if_spectral_netlink.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2011,2017 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 <wlan_tgt_def_config.h>
+#include <hif.h>
+#include <hif_hw_version.h>
+#include <wmi_unified_api.h>
+#include <target_if_spectral.h>
+#include <wlan_lmac_if_def.h>
+#include <wlan_osif_priv.h>
+
+#ifdef HOST_OFFLOAD
+extern void
+atd_spectral_msg_send(
+ struct net_device *dev,
+ SPECTRAL_SAMP_MSG *msg,
+ uint16_t msg_len);
+#endif
+
+#ifdef SPECTRAL_USE_NETLINK_SOCKETS
+struct sock *target_if_spectral_nl_sock;
+static atomic_t spectral_nl_users = ATOMIC_INIT(0);
+
+#if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE)
+void target_if_spectral_nl_data_ready(struct sock *sk, int len)
+{
+ qdf_print("%s %d\n", __func__, __LINE__);
+}
+
+#else
+void target_if_spectral_nl_data_ready(struct sk_buff *skb)
+{
+ qdf_print("%s %d\n", __func__, __LINE__);
+}
+
+#endif /* VERSION */
+
+int target_if_spectral_init_netlink(struct target_if_spectral *spectral)
+{
+#if KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE
+
+ struct netlink_kernel_cfg cfg = {
+ .groups = 1,
+ .input = target_if_spectral_nl_data_ready,
+ };
+#endif
+
+ if (!spectral) {
+ qdf_print("%s: sc_spectral is NULL\n", __func__);
+ return -EIO;
+ }
+
+ spectral->spectral_sent_msg = 0;
+
+ if (!target_if_spectral_nl_sock) {
+#if KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE
+ target_if_spectral_nl_sock = (struct sock *)netlink_kernel_create(
+ &init_net,
+ NETLINK_ATHEROS,
+ &cfg);
+#elif KERNEL_VERSION(3, 6, 0) <= LINUX_VERSION_CODE
+ target_if_spectral_nl_sock = (struct sock *)netlink_kernel_create(
+ &init_net,
+ NETLINK_ATHEROS,
+ THIS_MODULE,
+ &cfg);
+#elif (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE)
+ target_if_spectral_nl_sock = (
+ struct sock *)netlink_kernel_create(NETLINK_ATHEROS,
+ 1,
+ &target_if_spectral_nl_data_ready,
+ THIS_MODULE);
+#else
+#if (KERNEL_VERSION(3, 10, 0) <= LINUX_VERSION_CODE)
+ struct netlink_kernel_cfg cfg;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.groups = 1;
+ cfg.input = &target_if_spectral_nl_data_ready;
+ target_if_spectral_nl_sock = (struct sock *)netlink_kernel_create(
+ &init_net, NETLINK_ATHEROS, &cfg);
+#else
+ target_if_spectral_nl_sock = (struct sock *)netlink_kernel_create(
+ &init_net,
+ NETLINK_ATHEROS,
+ 1,
+ &target_if_spectral_nl_data_ready,
+ NULL,
+ THIS_MODULE);
+#endif
+#endif
+ if (!target_if_spectral_nl_sock) {
+ qdf_print("%s NETLINK_KERNEL_CREATE FAILED\n", __func__);
+ return -ENODEV;
+ }
+ }
+ atomic_inc(&spectral_nl_users);
+ spectral->spectral_sock = target_if_spectral_nl_sock;
+
+ if ((!spectral) || (!spectral->spectral_sock)) {
+ qdf_print("%s NULL pointers (spectral=%d) (sock=%d)\n",
+ __func__, (!spectral), (!spectral->spectral_sock));
+ return -ENODEV;
+ }
+ if (!spectral->spectral_skb)
+ qdf_print(KERN_ERR "%s %d NULL SKB\n", __func__, __LINE__);
+
+ return 0;
+}
+
+int target_if_spectral_destroy_netlink(struct target_if_spectral *spectral)
+{
+ spectral->spectral_sock = NULL;
+ if (atomic_dec_and_test(&spectral_nl_users)) {
+ sock_release(target_if_spectral_nl_sock->sk_socket);
+ target_if_spectral_nl_sock = NULL;
+ }
+ return 0;
+}
+
+#endif /* SPECTRAL_USE_NETLINK_SOCKETS */
+
+static void spectral_process_noise_pwr_report(
+ struct target_if_spectral *spectral,
+ const SPECTRAL_SAMP_MSG *spec_samp_msg)
+{
+ int i, done;
+
+/*
+ * qdf_print(
+ * "%s: #%d/%d datalen=%d tstamp=%x last_tstamp=%x "
+ * "rssi=%d nb_lower=%d peak=%d\n",
+ * __func__, spectral->noise_pwr_reports_recv,
+ * spectral->noise_pwr_reports_reqd,
+ * spec_samp_msg->samp_data.spectral_data_len,
+ * spec_samp_msg->samp_data.spectral_tstamp,
+ * spec_samp_msg->samp_data.spectral_last_tstamp,
+ * spec_samp_msg->samp_data.spectral_lower_rssi,
+ * spec_samp_msg->samp_data.spectral_nb_lower,
+ * spec_samp_msg->samp_data.spectral_lower_max_index);
+ */
+
+ qdf_spin_lock(&spectral->noise_pwr_reports_lock);
+
+ if (!spectral->noise_pwr_reports_reqd) {
+ qdf_spin_unlock(&spectral->noise_pwr_reports_lock);
+ return;
+ }
+
+ if (spectral->noise_pwr_reports_recv <
+ spectral->noise_pwr_reports_reqd) {
+ spectral->noise_pwr_reports_recv++;
+
+/*
+ * qdf_print(
+ * "#%d/%d: rssi=%3d,%3d,%3d %3d,%3d,%3d\n",
+ * spectral->noise_pwr_reports_recv,
+ * spectral->noise_pwr_reports_reqd,
+ * spec_samp_msg->samp_data.spectral_chain_ctl_rssi[0],
+ * spec_samp_msg->samp_data.spectral_chain_ctl_rssi[1],
+ * spec_samp_msg->samp_data.spectral_chain_ctl_rssi[2],
+ * spec_samp_msg->samp_data.spectral_chain_ext_rssi[0],
+ * spec_samp_msg->samp_data.spectral_chain_ext_rssi[1],
+ * spec_samp_msg->samp_data.spectral_chain_ext_rssi[2]);
+ */
+
+ for (i = 0; i < ATH_HOST_MAX_ANTENNA; i++) {
+ uint32_t index;
+
+ if (spectral->noise_pwr_chain_ctl[i]) {
+ index = spectral->noise_pwr_chain_ctl[i]->rptcount++;
+ spectral->noise_pwr_chain_ctl[i]->pwr[index] =
+ spec_samp_msg->samp_data.spectral_chain_ctl_rssi[i];
+ }
+ if (spectral->noise_pwr_chain_ext[i]) {
+ index = spectral->noise_pwr_chain_ext[i]->rptcount++;
+ spectral->noise_pwr_chain_ext[i]->pwr[index] =
+ spec_samp_msg->samp_data.spectral_chain_ext_rssi[i];
+ }
+ }
+ }
+
+ done = (spectral->noise_pwr_reports_recv >=
+ spectral->noise_pwr_reports_reqd);
+
+ qdf_spin_unlock(&spectral->noise_pwr_reports_lock);
+
+ if (done) {
+ qdf_spin_lock(&spectral->ath_spectral_lock);
+ target_if_stop_spectral_scan(spectral->pdev_obj);
+ spectral->sc_spectral_scan = 0;
+ qdf_spin_unlock(&spectral->ath_spectral_lock);
+
+/*
+ * qdf_print(
+ * "%s: done: %d/%d recv - set sc_spectral_scan = 0\n",
+ * __func__, spectral->noise_pwr_reports_recv,
+ * spectral->noise_pwr_reports_reqd);
+ */
+ }
+}
+
+/*
+ * Function : spectral_create_samp_msg
+ * Description : create SAMP message and send it host
+ * Input :
+ * Output :
+ *
+ */
+
+void target_if_spectral_create_samp_msg(
+ struct target_if_spectral *spectral,
+ struct target_if_samp_msg_params *params)
+{
+ /*
+ * XXX : Non-Rentrant. Will be an issue with dual concurrent
+ * operation on multi-processor system
+ */
+
+ int temp_samp_msg_len = 0;
+
+ static SPECTRAL_SAMP_MSG spec_samp_msg;
+
+ SPECTRAL_SAMP_MSG *msg = NULL;
+ SPECTRAL_SAMP_DATA *data = NULL;
+ u_int8_t *bin_pwr_data = NULL;
+ SPECTRAL_CLASSIFIER_PARAMS *cp = NULL;
+ SPECTRAL_CLASSIFIER_PARAMS *pcp = NULL;
+ struct target_if_spectral_ops *p_sops = NULL;
+ struct target_if_spectral_skb_event *sp_skb_event = NULL;
+
+#ifdef SPECTRAL_USE_NETLINK_SOCKETS
+ static int samp_msg_index;
+#endif
+
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+
+ temp_samp_msg_len = sizeof(SPECTRAL_SAMP_MSG) -
+ (MAX_NUM_BINS * sizeof(u_int8_t));
+ temp_samp_msg_len += (params->pwr_count * sizeof(u_int8_t));
+ if (spectral->ch_width == IEEE80211_CWM_WIDTH160)
+ temp_samp_msg_len +=
+ (params->pwr_count_sec80 * sizeof(u_int8_t));
+ bin_pwr_data = params->bin_pwr_data;
+
+ memset(&spec_samp_msg, 0, sizeof(SPECTRAL_SAMP_MSG));
+
+ data = &spec_samp_msg.samp_data;
+
+ spec_samp_msg.signature = SPECTRAL_SIGNATURE;
+ spec_samp_msg.freq = params->freq;
+ spec_samp_msg.freq_loading = params->freq_loading;
+ spec_samp_msg.samp_data.spectral_data_len = params->datalen;
+ spec_samp_msg.samp_data.spectral_rssi = params->rssi;
+ spec_samp_msg.samp_data.ch_width = spectral->ch_width;
+
+ spec_samp_msg.samp_data.spectral_combined_rssi =
+ (u_int8_t)params->rssi;
+ spec_samp_msg.samp_data.spectral_upper_rssi = params->upper_rssi;
+ spec_samp_msg.samp_data.spectral_lower_rssi = params->lower_rssi;
+
+ OS_MEMCPY(
+ spec_samp_msg.samp_data.spectral_chain_ctl_rssi,
+ params->chain_ctl_rssi,
+ sizeof(params->chain_ctl_rssi));
+ OS_MEMCPY(
+ spec_samp_msg.samp_data.spectral_chain_ext_rssi,
+ params->chain_ext_rssi,
+ sizeof(params->chain_ext_rssi));
+
+ spec_samp_msg.samp_data.spectral_bwinfo = params->bwinfo;
+ spec_samp_msg.samp_data.spectral_tstamp = params->tstamp;
+ spec_samp_msg.samp_data.spectral_max_index = params->max_index;
+
+ /* Classifier in user space needs access to these */
+ spec_samp_msg.samp_data.spectral_lower_max_index =
+ params->max_lower_index;
+ spec_samp_msg.samp_data.spectral_upper_max_index =
+ params->max_upper_index;
+ spec_samp_msg.samp_data.spectral_nb_lower =
+ params->nb_lower;
+ spec_samp_msg.samp_data.spectral_nb_upper = params->nb_upper;
+ spec_samp_msg.samp_data.spectral_last_tstamp =
+ params->last_tstamp;
+ spec_samp_msg.samp_data.spectral_max_mag = params->max_mag;
+ spec_samp_msg.samp_data.bin_pwr_count =
+ params->pwr_count;
+ spec_samp_msg.samp_data.lb_edge_extrabins =
+ spectral->lb_edge_extrabins;
+ spec_samp_msg.samp_data.rb_edge_extrabins =
+ spectral->rb_edge_extrabins;
+ spec_samp_msg.samp_data.spectral_combined_rssi = params->rssi;
+ spec_samp_msg.samp_data.spectral_max_scale = params->max_exp;
+
+#ifdef SPECTRAL_USE_NETLINK_SOCKETS
+
+ /*
+ * This is a dirty hack to get the Windows build pass.
+ * Currently Windows and Linux builds source spectral_data.h
+ * form two different place. The windows version do not
+ * have noise_floor member in it.
+ *
+ * As a temp workaround this variable is set under the
+ * SPECTRAL_USE_NETLINK_SOCKETS as this is called only
+ * under the linux build and this saves the day
+ *
+ * The plan to sync of header files in under the way
+ *
+ */
+
+ spec_samp_msg.samp_data.noise_floor = params->noise_floor;
+#endif /* SPECTRAL_USE_NETLINK_SOCKETS */
+
+ /* Classifier in user space needs access to these */
+ cp = &spec_samp_msg.samp_data.classifier_params;
+ pcp = ¶ms->classifier_params;
+
+ OS_MEMCPY(cp, pcp, sizeof(SPECTRAL_CLASSIFIER_PARAMS));
+
+ SPECTRAL_MSG_COPY_CHAR_ARRAY(
+ &data->bin_pwr[0],
+ bin_pwr_data,
+ params->pwr_count);
+
+#ifdef SPECTRAL_USE_NETLINK_SOCKETS
+ spec_samp_msg.vhtop_ch_freq_seg1 =
+ params->vhtop_ch_freq_seg1;
+ spec_samp_msg.vhtop_ch_freq_seg2 =
+ params->vhtop_ch_freq_seg2;
+
+ if (spectral->ch_width == IEEE80211_CWM_WIDTH160) {
+ spec_samp_msg.samp_data.spectral_rssi_sec80 = params->rssi_sec80;
+ spec_samp_msg.samp_data.noise_floor_sec80 = params->noise_floor_sec80;
+
+ spec_samp_msg.samp_data.spectral_data_len_sec80 =
+ params->datalen_sec80;
+ spec_samp_msg.samp_data.spectral_max_index_sec80 =
+ params->max_index_sec80;
+ spec_samp_msg.samp_data.spectral_max_mag_sec80 =
+ params->max_mag_sec80;
+ spec_samp_msg.samp_data.bin_pwr_count_sec80 =
+ params->pwr_count_sec80;
+ SPECTRAL_MSG_COPY_CHAR_ARRAY(&data->bin_pwr_sec80[0],
+ (params->bin_pwr_data_sec80),
+ params->pwr_count_sec80);
+
+ /* Note: REVERSE_ORDER is not a known use case for secondary 80 data at
+ * this point.
+ */
+ }
+#endif /* SPECTRAL_USE_NETLINK_SOCKETS */
+
+#ifdef SPECTRAL_CLASSIFIER_IN_KERNEL
+ if (params->interf_list.count)
+ OS_MEMCPY(
+ &data->interf_list,
+ ¶ms->interf_list,
+ sizeof(struct INTERF_SRC_RSP));
+ else
+#endif
+ data->interf_list.count = 0;
+
+#ifdef SPECTRAL_USE_NETLINK_SOCKETS
+ target_if_spectral_prep_skb(spectral);
+ if (spectral->spectral_skb) {
+ p_sops->get_mac_address(spectral, spec_samp_msg.macaddr);
+ spectral->spectral_nlh =
+ (struct nlmsghdr *)spectral->spectral_skb->data;
+ memcpy(NLMSG_DATA(spectral->spectral_nlh),
+ &spec_samp_msg,
+ sizeof(SPECTRAL_SAMP_MSG));
+ msg = (SPECTRAL_SAMP_MSG *)NLMSG_DATA(spectral->spectral_nlh);
+ /* Broadcast spectral data only if it is a edma supported device */
+ if (!spectral->sc_spectral_non_edma)
+ target_if_spectral_bcast_msg(spectral);
+ samp_msg_index++;
+ }
+
+ /* Check if the device is non-edma and follow the required broadcast
+ * path if true
+ */
+ if (spectral->sc_spectral_non_edma) {
+ /* Allocating memory for the queue entity to hold the spectral socket
+ * buffer
+ */
+ sp_skb_event = (struct target_if_spectral_skb_event
+ *)qdf_mem_malloc(sizeof(struct target_if_spectral_skb_event));
+
+ if (sp_skb_event) {
+ OS_MEMZERO(
+ sp_skb_event,
+ sizeof(struct target_if_spectral_skb_event));
+ sp_skb_event->sp_skb = spectral->spectral_skb;
+ sp_skb_event->sp_nlh = spectral->spectral_nlh;
+ spectral->spectral_skb = NULL;
+ spectral->spectral_nlh = NULL;
+
+ /* Queue spectral socket buffers to be broadcasted outside irq
+ * lock
+ */
+ qdf_spin_lock(&spectral->spectral_skbqlock);
+ STAILQ_INSERT_TAIL(
+ &spectral->spectral_skbq,
+ sp_skb_event,
+ spectral_skb_list);
+ qdf_spin_unlock(&spectral->spectral_skbqlock);
+ }
+ }
+#else
+ /*
+ * call the indicate function to pass the data to the net layer
+ * Windows will pass to a spectral WIN32 service
+ */
+ msg = (SPECTRAL_SAMP_MSG *)qdf_mem_malloc(sizeof(SPECTRAL_SAMP_MSG));
+ if (msg) {
+ OS_MEMCPY(msg, &spec_samp_msg, sizeof(SPECTRAL_SAMP_MSG));
+ ath_spectral_indicate(
+ params->sc,
+ (void *)msg,
+ sizeof(SPECTRAL_SAMP_MSG));
+ OS_FREE(msg);
+ msg = NULL;
+ } else {
+ qdf_print("No buffer\n");
+ }
+#endif /* SPECTRAL_USE_NETLINK_SOCKETS */
+
+#ifdef HOST_OFFLOAD
+ atd_spectral_msg_send(spectral->ic->ic_osdev->netdev,
+ &spec_samp_msg,
+ sizeof(SPECTRAL_SAMP_MSG));
+#endif
+
+ if (spectral->sc_spectral_noise_pwr_cal)
+ spectral_process_noise_pwr_report(spectral, &spec_samp_msg);
+}
+
+#ifdef SPECTRAL_USE_NETLINK_SOCKETS
+
+void target_if_spectral_prep_skb(struct target_if_spectral *spectral)
+{
+ spectral->spectral_skb = dev_alloc_skb(MAX_SPECTRAL_PAYLOAD);
+
+ if (spectral->spectral_skb) {
+ skb_put(spectral->spectral_skb, MAX_SPECTRAL_PAYLOAD);
+ spectral->spectral_nlh =
+ (struct nlmsghdr *)spectral->spectral_skb->data;
+
+ OS_MEMZERO(spectral->spectral_nlh, sizeof(*spectral->spectral_nlh));
+
+ /* Possible bug that size of SPECTRAL_SAMP_MSG and SPECTRAL_MSG
+ * differ by 3 bytes so we miss 3 bytes
+ */
+
+ spectral->spectral_nlh->nlmsg_len =
+ NLMSG_SPACE(sizeof(SPECTRAL_SAMP_MSG));
+ spectral->spectral_nlh->nlmsg_pid = 0;
+ spectral->spectral_nlh->nlmsg_flags = 0;
+ } else {
+ spectral->spectral_skb = NULL;
+ spectral->spectral_nlh = NULL;
+ }
+}
+
+void target_if_spectral_unicast_msg(struct target_if_spectral *spectral)
+{
+ if (!spectral) {
+ qdf_print("%s Spectral is NULL\n", __func__);
+ return;
+ }
+
+ if (!spectral->spectral_sock) {
+ qdf_print("%s Spectral Socket is invalid\n", __func__);
+ dev_kfree_skb(spectral->spectral_skb);
+ spectral->spectral_skb = NULL;
+ return;
+ }
+
+ if (spectral->spectral_skb) {
+#if (KERNEL_VERSION(2, 6, 31) > LINUX_VERSION_CODE)
+ NETLINK_CB(spectral->spectral_skb).dst_pid = spectral->spectral_pid;
+#endif /* VERSION - field depracated by newer kernel */
+#if KERNEL_VERSION(3, 7, 0) > LINUX_VERSION_CODE
+ NETLINK_CB(spectral->spectral_skb).pid = 0; /* from kernel */
+#else
+ NETLINK_CB(spectral->spectral_skb).portid = 0; /* from kernel */
+#endif
+ /* to mcast group 1<<0 */
+ NETLINK_CB(spectral->spectral_skb).dst_group = 0;
+
+ netlink_unicast(
+ spectral->spectral_sock,
+ spectral->spectral_skb,
+ spectral->spectral_pid,
+ MSG_DONTWAIT);
+ }
+}
+
+/*
+ * Function : target_if_spectral_bcast_msg
+ * Description : Passes the Spectral Message to Host
+ * Input : Pointer to spectral
+ * Output : Void
+ *
+ */
+void target_if_spectral_bcast_msg(struct target_if_spectral *spectral)
+{
+#if (KERNEL_VERSION(2, 6, 31) >= LINUX_VERSION_CODE)
+ fd_set write_set;
+#endif
+ SPECTRAL_SAMP_MSG *msg = NULL;
+ struct nlmsghdr *nlh = NULL;
+ int status;
+
+#if (KERNEL_VERSION(2, 6, 31) >= LINUX_VERSION_CODE)
+ FD_ZERO(&write_set);
+#endif
+
+ if (!spectral)
+ return;
+
+ if (!spectral->spectral_sock) {
+ dev_kfree_skb(spectral->spectral_skb);
+ spectral->spectral_skb = NULL;
+ return;
+ }
+
+ if (!spectral->spectral_skb)
+ return;
+
+ nlh = (struct nlmsghdr *)spectral->spectral_skb->data;
+ msg = (SPECTRAL_SAMP_MSG *)NLMSG_DATA(spectral->spectral_nlh);
+ /* print_samp_msg (msg, sc); */
+ status = target_if_send_phydata(
+ spectral->pdev_obj,
+ spectral->spectral_sock,
+ spectral->spectral_skb);
+ if (status == 0)
+ spectral->spectral_sent_msg++;
+
+ /* netlink will have freed the skb */
+ if (spectral->spectral_skb)
+ spectral->spectral_skb = NULL;
+}
+
+void target_if_spectral_skb_dequeue(unsigned long data)
+{
+ struct target_if_spectral *spectral =
+ (struct target_if_spectral *)data;
+ struct target_if_spectral_skb_event *sp_skb_event = NULL;
+
+ qdf_spin_lock(&spectral->spectral_skbqlock);
+ /* Deque all the spectral socket buffers queued */
+ while (!STAILQ_EMPTY(&spectral->spectral_skbq)) {
+ sp_skb_event = STAILQ_FIRST(&spectral->spectral_skbq);
+ if (sp_skb_event) {
+ spectral->spectral_skb = sp_skb_event->sp_skb;
+ spectral->spectral_nlh = sp_skb_event->sp_nlh;
+ STAILQ_REMOVE_HEAD(
+ &spectral->spectral_skbq,
+ spectral_skb_list);
+ qdf_spin_unlock(&spectral->spectral_skbqlock);
+ OS_FREE(sp_skb_event);
+ /* Broadcast spectral data after dequeing */
+ target_if_spectral_bcast_msg(spectral);
+ qdf_spin_lock(&spectral->spectral_skbqlock);
+ }
+ }
+ qdf_spin_unlock(&spectral->spectral_skbqlock);
+}
+
+#endif /* SPECTRAL_USE_NETLINK_SOCKETS */
+
diff --git a/target_if/spectral/target_if_spectral_phyerr.c b/target_if/spectral/target_if_spectral_phyerr.c
new file mode 100644
index 0000000..6f534b7
--- /dev/null
+++ b/target_if/spectral/target_if_spectral_phyerr.c
@@ -0,0 +1,1653 @@
+/*
+ * Copyright (c) 2011,2017 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 <qdf_types.h>
+#include <wlan_tgt_def_config.h>
+#include <hif.h>
+#include <hif_hw_version.h>
+#include <wmi_unified_api.h>
+#include <target_if_spectral.h>
+#include <wlan_lmac_if_def.h>
+#include <wlan_osif_priv.h>
+#include <osif_rawmode_sim.h>
+/* START of spectral GEN II HW specific function declarations */
+static int dump_summary_report_gen2(
+ SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
+ int tlvlen,
+ bool is_160_format);
+static int process_search_fft_report_gen2(
+ SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
+ int tlvlen,
+ SPECTRAL_SEARCH_FFT_INFO_GEN2 *p_fft_info);
+static int dump_adc_report_gen2(SPECTRAL_PHYERR_TLV_GEN2 *ptlv, int tlvlen);
+static int dump_search_fft_report_gen2(
+ SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
+ int tlvlen,
+ bool is_160_format);
+/* END of spectral GEN II HW specific function declarations */
+
+#if WLAN_SPECTRAL_ENABLE
+
+/*
+ * Function : print_buf
+ * Description : Prints given buffer for given length
+ * Input : Pointer to buffer and length
+ * Output : Void
+ *
+ */
+static void print_buf(u_int8_t *pbuf, int len)
+{
+ int i = 0;
+
+ for (i = 0; i < len; i++) {
+ qdf_print("%02X ", pbuf[i]);
+ if (i % 32 == 31)
+ qdf_print("\n");
+ }
+}
+
+/*
+ * Function : target_if_spectral_dump_fft
+ * Description : Dump Spectral FFT
+ * Input : Pointer to Spectral Phyerr FFT
+ * Output : Success/Failure
+ *
+ */
+int target_if_spectral_dump_fft(u_int8_t *pfft, int fftlen)
+{
+ int i = 0;
+
+ /* TODO : Do not delete the following print
+ * The scripts used to validate Spectral depend on this Print
+ */
+ qdf_print("SPECTRAL : FFT Length is 0x%x (%d)\n", fftlen, fftlen);
+
+ qdf_print("fft_data # ");
+ for (i = 0; i < fftlen; i++) {
+ qdf_print("%d ", pfft[i]);
+ /* if (i % 32 == 31)
+ * qdf_print("\n");
+ */
+ }
+ qdf_print("\n");
+ return 0;
+}
+
+/*
+ * Function : target_if_spectral_send_tlv_to_host
+ * Description : Send the TLV information to Host
+ * Input : Pointer to the TLV
+ * Output : Success/Failure
+ *
+ */
+
+#ifdef HOST_OFFLOAD
+extern void
+atd_spectral_msg_send(
+ struct net_device *dev,
+ SPECTRAL_SAMP_MSG *msg,
+ uint16_t msg_len);
+#endif
+
+int target_if_spectral_send_tlv_to_host(
+ struct target_if_spectral *spectral,
+ u_int8_t *data,
+ u_int32_t datalen)
+{
+ int status = true;
+
+ target_if_spectral_prep_skb(spectral);
+ if (spectral->spectral_skb) {
+ spectral->spectral_nlh =
+ (struct nlmsghdr *)spectral->spectral_skb->data;
+ memcpy(NLMSG_DATA(spectral->spectral_nlh), data, datalen);
+ target_if_spectral_bcast_msg(spectral);
+ } else {
+ status = false;
+ }
+#ifdef HOST_OFFLOAD
+ atd_spectral_msg_send(spectral->ic->ic_osdev->netdev,
+ data,
+ datalen);
+#endif
+ return status;
+}
+
+/*
+ * Function : dbg_print_SAMP_param
+ * Description : Print contents of SAMP struct
+ * Input : Pointer to SAMP message
+ * Output : Void
+ *
+ */
+void target_if_dbg_print_SAMP_param(struct target_if_samp_msg_params *p)
+{
+ qdf_print("\nSAMP Packet : -------------------- START --------------"
+ "------\n");
+ qdf_print("Freq = %d\n", p->freq);
+ qdf_print("RSSI = %d\n", p->rssi);
+ qdf_print("Bin Count = %d\n", p->pwr_count);
+ qdf_print("Timestamp = %d\n", p->tstamp);
+ qdf_print("SAMP Packet : -------------------- END ------------------"
+ "-----\n");
+}
+
+/*
+ * Function : dbg_print_SAMP_msg
+ * Description : Print contents of SAMP Message
+ * Input : Pointer to SAMP message
+ * Output : Void
+ *
+ */
+void target_if_dbg_print_SAMP_msg(SPECTRAL_SAMP_MSG *ss_msg)
+{
+ int i = 0;
+
+ SPECTRAL_SAMP_DATA *p = &ss_msg->samp_data;
+ SPECTRAL_CLASSIFIER_PARAMS *pc = &p->classifier_params;
+ struct INTERF_SRC_RSP *pi = &p->interf_list;
+
+ line();
+ qdf_print("Spectral Message\n");
+ line();
+ qdf_print("Signature : 0x%x\n", ss_msg->signature);
+ qdf_print("Freq : %d\n", ss_msg->freq);
+ qdf_print("Freq load : %d\n", ss_msg->freq_loading);
+ qdf_print("Intfnc type : %d\n", ss_msg->int_type);
+ line();
+ qdf_print("Spectral Data info\n");
+ line();
+ qdf_print("data length : %d\n", p->spectral_data_len);
+ qdf_print("rssi : %d\n", p->spectral_rssi);
+ qdf_print("combined rssi : %d\n", p->spectral_combined_rssi);
+ qdf_print("upper rssi : %d\n", p->spectral_upper_rssi);
+ qdf_print("lower rssi : %d\n", p->spectral_lower_rssi);
+ qdf_print("bw info : %d\n", p->spectral_bwinfo);
+ qdf_print("timestamp : %d\n", p->spectral_tstamp);
+ qdf_print("max index : %d\n", p->spectral_max_index);
+ qdf_print("max exp : %d\n", p->spectral_max_exp);
+ qdf_print("max mag : %d\n", p->spectral_max_mag);
+ qdf_print("last timstamp : %d\n", p->spectral_last_tstamp);
+ qdf_print("upper max idx : %d\n", p->spectral_upper_max_index);
+ qdf_print("lower max idx : %d\n", p->spectral_lower_max_index);
+ qdf_print("bin power count : %d\n", p->bin_pwr_count);
+ line();
+ qdf_print("Classifier info\n");
+ line();
+ qdf_print("20/40 Mode : %d\n", pc->spectral_20_40_mode);
+ qdf_print("dc index : %d\n", pc->spectral_dc_index);
+ qdf_print("dc in MHz : %d\n", pc->spectral_dc_in_mhz);
+ qdf_print("upper channel : %d\n", pc->upper_chan_in_mhz);
+ qdf_print("lower channel : %d\n", pc->lower_chan_in_mhz);
+ line();
+ qdf_print("Interference info\n");
+ line();
+ qdf_print("inter count : %d\n", pi->count);
+
+ for (i = 0; i < pi->count; i++) {
+ qdf_print("inter type : %d\n", pi->interf[i].interf_type);
+ qdf_print("min freq : %d\n", pi->interf[i].interf_min_freq);
+ qdf_print("max freq : %d\n", pi->interf[i].interf_max_freq);
+ }
+}
+
+/*
+ * Function : get_offset_swar_sec80
+ * Description : Get offset for SWAR according to the channel width
+ * Input : Channel width
+ * Output : Offset for SWAR algorithm
+ */
+uint32_t target_if_get_offset_swar_sec80(uint32_t channel_width)
+{
+ uint32_t offset = 0;
+
+ switch (channel_width) {
+ case IEEE80211_CWM_WIDTH20:
+ offset = OFFSET_CH_WIDTH_20;
+ break;
+ case IEEE80211_CWM_WIDTH40:
+ offset = OFFSET_CH_WIDTH_40;
+ break;
+ case IEEE80211_CWM_WIDTH80:
+ offset = OFFSET_CH_WIDTH_80;
+ break;
+ case IEEE80211_CWM_WIDTH160:
+ offset = OFFSET_CH_WIDTH_160;
+ break;
+ default:
+ offset = OFFSET_CH_WIDTH_80;
+ break;
+ }
+ return offset;
+}
+
+/* START of spectral GEN II HW specific functions */
+
+/*
+ * Function : dump_summary_report_gen2
+ * Description : Dump Spectral Summary Report
+ * Input : Pointer to Spectral Phyerr TLV and Length, flag indicating
+ * whether information provided by HW is in altered format for
+ * 802.11ac 160/80+80 MHz support (QCA9984 onwards).
+ * Output : Success/Failure
+ *
+ */
+int dump_summary_report_gen2(
+ SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
+ int tlvlen,
+ bool is_160_format)
+{
+ /* For simplicity, everything is defined as uint32_t (except one).
+ * Proper code will later use the right sizes.
+ */
+
+ /* For easy comparision between MDK team and OS team, the MDK script
+ * variable names have been used
+ */
+
+ uint32_t agc_mb_gain;
+ uint32_t sscan_gidx;
+ uint32_t agc_total_gain;
+ uint32_t recent_rfsat;
+ uint32_t ob_flag;
+ uint32_t nb_mask;
+ uint32_t peak_mag;
+ int16_t peak_inx;
+
+ uint32_t ss_summary_A = 0;
+ uint32_t ss_summary_B = 0;
+ uint32_t ss_summary_C = 0;
+ uint32_t ss_summary_D = 0;
+ uint32_t ss_summary_E = 0;
+ SPECTRAL_PHYERR_HDR_GEN2 *phdr =
+ (SPECTRAL_PHYERR_HDR_GEN2 *)((u_int8_t *)ptlv +
+ sizeof(SPECTRAL_PHYERR_TLV_GEN2));
+
+ qdf_print("SPECTRAL : SPECTRAL SUMMARY REPORT\n");
+
+ if (is_160_format) {
+ if (tlvlen != 20) {
+ qdf_print("SPECTRAL : Unexpected TLV length %d for Spectral "
+ "Summary Report! Hexdump follows\n", tlvlen);
+ print_buf((u_int8_t *)ptlv, tlvlen + 4);
+ return -EPERM;
+ }
+
+ /* Doing copy as the contents may not be aligned */
+ qdf_mem_copy(&ss_summary_A, (u_int8_t *)phdr, sizeof(int));
+ qdf_mem_copy(
+ &ss_summary_B,
+ (u_int8_t *)((u_int8_t *)phdr + sizeof(int)),
+ sizeof(int));
+ qdf_mem_copy(
+ &ss_summary_C,
+ (u_int8_t *)((u_int8_t *)phdr + 2 * sizeof(int)),
+ sizeof(int));
+ qdf_mem_copy(
+ &ss_summary_D,
+ (u_int8_t *)((u_int8_t *)phdr + 3 * sizeof(int)),
+ sizeof(int));
+ qdf_mem_copy(
+ &ss_summary_E,
+ (u_int8_t *)((u_int8_t *)phdr + 4 * sizeof(int)),
+ sizeof(int));
+
+ /*The following is adapted from MDK scripts for easier comparability */
+
+ recent_rfsat = ((ss_summary_A >> 8) & 0x1);
+ sscan_gidx = (ss_summary_A & 0xff);
+ printf("sscan_gidx=%d, is_recent_rfsat=%d\n",
+ sscan_gidx, recent_rfsat);
+
+ /* First segment */
+ agc_mb_gain = ((ss_summary_B >> 10) & 0x7f);
+ agc_total_gain = (ss_summary_B & 0x3ff);
+ nb_mask = ((ss_summary_C >> 22) & 0xff);
+ ob_flag = ((ss_summary_B >> 17) & 0x1);
+ peak_inx = (ss_summary_C & 0xfff);
+ if (peak_inx > 2047)
+ peak_inx = peak_inx - 4096;
+ peak_mag = ((ss_summary_C >> 12) & 0x3ff);
+
+ printf("agc_total_gain_segid0 = 0x%.2x, agc_mb_gain_segid0=%d\n",
+ agc_total_gain, agc_mb_gain);
+ printf("nb_mask_segid0 = 0x%.2x, ob_flag_segid0=%d, "
+ "peak_index_segid0=%d, peak_mag_segid0=%d\n",
+ nb_mask, ob_flag, peak_inx, peak_mag);
+
+ /* Second segment */
+ agc_mb_gain = ((ss_summary_D >> 10) & 0x7f);
+ agc_total_gain = (ss_summary_D & 0x3ff);
+ nb_mask = ((ss_summary_E >> 22) & 0xff);
+ ob_flag = ((ss_summary_D >> 17) & 0x1);
+ peak_inx = (ss_summary_E & 0xfff);
+ if (peak_inx > 2047)
+ peak_inx = peak_inx - 4096;
+ peak_mag = ((ss_summary_E >> 12) & 0x3ff);
+
+ printf("agc_total_gain_segid1 = 0x%.2x, agc_mb_gain_segid1=%d\n",
+ agc_total_gain, agc_mb_gain);
+ printf("nb_mask_segid1 = 0x%.2x, ob_flag_segid1=%d, "
+ "peak_index_segid1=%d, peak_mag_segid1=%d\n",
+ nb_mask, ob_flag, peak_inx, peak_mag);
+ } else {
+ if (tlvlen != 8) {
+ qdf_print("SPECTRAL : Unexpected TLV length %d for Spectral "
+ "Summary Report! Hexdump follows\n", tlvlen);
+ print_buf((u_int8_t *)ptlv, tlvlen + 4);
+ return -EPERM;
+ }
+
+ /* Doing copy as the contents may not be aligned */
+ qdf_mem_copy(&ss_summary_A, (u_int8_t *)phdr, sizeof(int));
+ qdf_mem_copy(
+ &ss_summary_B,
+ (u_int8_t *)((u_int8_t *)phdr + sizeof(int)),
+ sizeof(int));
+
+ nb_mask = ((ss_summary_B >> 22) & 0xff);
+ ob_flag = ((ss_summary_B >> 30) & 0x1);
+ peak_inx = (ss_summary_B & 0xfff);
+
+ if (peak_inx > 2047)
+ peak_inx = peak_inx - 4096;
+
+ peak_mag = ((ss_summary_B >> 12) & 0x3ff);
+ agc_mb_gain = ((ss_summary_A >> 24) & 0x7f);
+ agc_total_gain = (ss_summary_A & 0x3ff);
+ sscan_gidx = ((ss_summary_A >> 16) & 0xff);
+ recent_rfsat = ((ss_summary_B >> 31) & 0x1);
+
+ qdf_print("nb_mask = 0x%.2x, ob_flag=%d, peak_index=%d, peak_mag=%d, "
+ "agc_mb_gain=%d, agc_total_gain=%d, sscan_gidx=%d, "
+ "recent_rfsat=%d\n",
+ nb_mask, ob_flag, peak_inx, peak_mag, agc_mb_gain,
+ agc_total_gain, sscan_gidx, recent_rfsat);
+ }
+
+ return 0;
+}
+
+/*
+ * Function : process_search_fft_report_gen2
+ * Description : Process Search FFT Report
+ * Input : Pointer to Spectral Phyerr TLV and Length and pointer to
+ * search fft info
+ * Output : Success/Failure
+ *
+ */
+int process_search_fft_report_gen2(
+ SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
+ int tlvlen,
+ SPECTRAL_SEARCH_FFT_INFO_GEN2 *p_fft_info)
+{
+ /* For simplicity, everything is defined as uint32_t (except one).
+ * Proper code will later use the right sizes.
+ */
+ /* For easy comparision between MDK team and OS team, the MDK script
+ * variable names have been used
+ */
+ uint32_t relpwr_db;
+ uint32_t num_str_bins_ib;
+ uint32_t base_pwr;
+ uint32_t total_gain_info;
+
+ uint32_t fft_chn_idx;
+ int16_t peak_inx;
+ uint32_t avgpwr_db;
+ uint32_t peak_mag;
+
+ uint32_t fft_summary_A = 0;
+ uint32_t fft_summary_B = 0;
+ u_int8_t *tmp = (u_int8_t *)ptlv;
+ SPECTRAL_PHYERR_HDR_GEN2 *phdr =
+ (SPECTRAL_PHYERR_HDR_GEN2 *)(tmp + sizeof(SPECTRAL_PHYERR_TLV_GEN2));
+
+ /* Relook this */
+ if (tlvlen < 8) {
+ qdf_print("SPECTRAL : Unexpected TLV length %d for Spectral "
+ "Summary Report! Hexdump follows\n", tlvlen);
+ print_buf((u_int8_t *)ptlv, tlvlen + 4);
+ return -EPERM;
+ }
+
+ /* Doing copy as the contents may not be aligned */
+ qdf_mem_copy(&fft_summary_A, (u_int8_t *)phdr, sizeof(int));
+ qdf_mem_copy(
+ &fft_summary_B,
+ (u_int8_t *)((u_int8_t *)phdr + sizeof(int)),
+ sizeof(int));
+
+ relpwr_db = ((fft_summary_B >> 26) & 0x3f);
+ num_str_bins_ib = fft_summary_B & 0xff;
+ base_pwr = ((fft_summary_A >> 14) & 0x1ff);
+ total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
+
+ fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
+ peak_inx = fft_summary_A & 0xfff;
+
+ if (peak_inx > 2047)
+ peak_inx = peak_inx - 4096;
+
+ avgpwr_db = ((fft_summary_B >> 18) & 0xff);
+ peak_mag = ((fft_summary_B >> 8) & 0x3ff);
+
+ /* Populate the Search FFT Info */
+ if (p_fft_info) {
+ p_fft_info->relpwr_db = relpwr_db;
+ p_fft_info->num_str_bins_ib = num_str_bins_ib;
+ p_fft_info->base_pwr = base_pwr;
+ p_fft_info->total_gain_info = total_gain_info;
+ p_fft_info->fft_chn_idx = fft_chn_idx;
+ p_fft_info->peak_inx = peak_inx;
+ p_fft_info->avgpwr_db = avgpwr_db;
+ p_fft_info->peak_mag = peak_mag;
+ }
+
+ return 0;
+}
+
+/*
+ * Function : dump_adc_report_gen2
+ * Description : Dump ADC Reports
+ * Input : Pointer to Spectral Phyerr TLV and Length
+ * Output : Success/Failure
+ *
+ */
+int dump_adc_report_gen2(SPECTRAL_PHYERR_TLV_GEN2 *ptlv, int tlvlen)
+{
+ int i;
+ uint32_t *pdata;
+ uint32_t data;
+
+ /* For simplicity, everything is defined as uint32_t (except one).
+ * Proper code will later use the right sizes.
+ */
+ uint32_t samp_fmt;
+ uint32_t chn_idx;
+ uint32_t recent_rfsat;
+ uint32_t agc_mb_gain;
+ uint32_t agc_total_gain;
+
+ uint32_t adc_summary = 0;
+
+ u_int8_t *ptmp = (u_int8_t *)ptlv;
+
+ qdf_print("SPECTRAL : ADC REPORT\n");
+
+ /* Relook this */
+ if (tlvlen < 4) {
+ qdf_print("Unexpected TLV length %d for ADC Report! Hexdump"
+ " follows\n", tlvlen);
+ print_buf((u_int8_t *)ptlv, tlvlen + 4);
+ return -EPERM;
+ }
+
+ qdf_mem_copy(&adc_summary, (u_int8_t *)(ptlv + 4), sizeof(int));
+
+ samp_fmt = ((adc_summary >> 28) & 0x1);
+ chn_idx = ((adc_summary >> 24) & 0x3);
+ recent_rfsat = ((adc_summary >> 23) & 0x1);
+ agc_mb_gain = ((adc_summary >> 16) & 0x7f);
+ agc_total_gain = adc_summary & 0x3ff;
+
+ qdf_print("samp_fmt= %u, chn_idx= %u, recent_rfsat= %u, agc_mb_gain=%u"
+ " agc_total_gain=%u\n", samp_fmt, chn_idx, recent_rfsat,
+ agc_mb_gain, agc_total_gain);
+
+ for (i = 0; i < (tlvlen / 4); i++) {
+ pdata = (uint32_t *)(ptmp + 4 + i * 4);
+ data = *pdata;
+
+ /* Interpreting capture format 1 */
+ if (1) {
+ uint8_t i1;
+ uint8_t q1;
+ uint8_t i2;
+ uint8_t q2;
+ int8_t si1;
+ int8_t sq1;
+ int8_t si2;
+ int8_t sq2;
+
+ i1 = data & 0xff;
+ q1 = (data >> 8) & 0xff;
+ i2 = (data >> 16) & 0xff;
+ q2 = (data >> 24) & 0xff;
+
+ if (i1 > 127)
+ si1 = i1 - 256;
+ else
+ si1 = i1;
+
+ if (q1 > 127)
+ sq1 = q1 - 256;
+ else
+ sq1 = q1;
+
+ if (i2 > 127)
+ si2 = i2 - 256;
+ else
+ si2 = i2;
+
+ if (q2 > 127)
+ sq2 = q2 - 256;
+ else
+ sq2 = q2;
+
+ qdf_print("SPECTRAL ADC : Interpreting capture format 1\n");
+ qdf_print("adc_data_format_1 # %d %d %d\n", 2 * i, si1, sq1);
+ qdf_print("adc_data_format_1 # %d %d %d\n",
+ 2 * i + 1, si2, sq2);
+ }
+
+ /* Interpreting capture format 0 */
+ if (1) {
+ uint16_t i1;
+ uint16_t q1;
+ int16_t si1;
+ int16_t sq1;
+
+ i1 = data & 0xffff;
+ q1 = (data >> 16) & 0xffff;
+ if (i1 > 32767)
+ si1 = i1 - 65536;
+ else
+ si1 = i1;
+
+ if (q1 > 32767)
+ sq1 = q1 - 65536;
+ else
+ sq1 = q1;
+ qdf_print("SPECTRAL ADC : Interpreting capture format 0\n");
+ qdf_print("adc_data_format_2 # %d %d %d\n", i, si1, sq1);
+ }
+ }
+
+ qdf_print("\n");
+
+ return 0;
+}
+
+/*
+ * Function : dump_search_fft_report_gen2
+ * Description : Process Search FFT Report
+ * Input : Pointer to Spectral Phyerr TLV and Length, flag indicating
+ * whether information provided by HW is in altered format for
+ * 802.11ac 160/80+80 MHz support (QCA9984 onwards).
+ * Output : Success/Failure
+ *
+ */
+int dump_search_fft_report_gen2(
+ SPECTRAL_PHYERR_TLV_GEN2 *ptlv,
+ int tlvlen,
+ bool is_160_format)
+{
+ int i;
+ uint32_t fft_mag;
+
+ /* For simplicity, everything is defined as uint32_t (except one).
+ * Proper code will later use the right sizes.
+ */
+ /* For easy comparision between MDK team and OS team, the MDK script
+ * variable names have been used
+ */
+ uint32_t relpwr_db;
+ uint32_t num_str_bins_ib;
+ uint32_t base_pwr;
+ uint32_t total_gain_info;
+
+ uint32_t fft_chn_idx;
+ int16_t peak_inx;
+ uint32_t avgpwr_db;
+ uint32_t peak_mag;
+ u_int8_t segid;
+
+ uint32_t fft_summary_A = 0;
+ uint32_t fft_summary_B = 0;
+ uint32_t fft_summary_C = 0;
+ u_int8_t *tmp = (u_int8_t *)ptlv;
+ SPECTRAL_PHYERR_HDR_GEN2 *phdr =
+ (SPECTRAL_PHYERR_HDR_GEN2 *)(tmp + sizeof(SPECTRAL_PHYERR_TLV_GEN2));
+ u_int32_t segid_skiplen = 0;
+
+ if (is_160_format)
+ segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
+
+ qdf_print("SPECTRAL : SEARCH FFT REPORT\n");
+
+ /* Relook this */
+ if (tlvlen < (8 + segid_skiplen)) {
+ qdf_print("SPECTRAL : Unexpected TLV length %d for Spectral "
+ "Summary Report! Hexdump follows\n", tlvlen);
+ print_buf((u_int8_t *)ptlv, tlvlen + 4);
+ return -EPERM;
+ }
+
+ /* Doing copy as the contents may not be aligned */
+ qdf_mem_copy(&fft_summary_A, (u_int8_t *)phdr, sizeof(int));
+ qdf_mem_copy(
+ &fft_summary_B,
+ (u_int8_t *)((u_int8_t *)phdr + sizeof(int)),
+ sizeof(int));
+ if (is_160_format)
+ qdf_mem_copy(
+ &fft_summary_C,
+ (u_int8_t *)((u_int8_t *)phdr + 2 * sizeof(int)),
+ sizeof(int));
+
+ relpwr_db = ((fft_summary_B >> 26) & 0x3f);
+ num_str_bins_ib = fft_summary_B & 0xff;
+ base_pwr = ((fft_summary_A >> 14) & 0x1ff);
+ total_gain_info = ((fft_summary_A >> 23) & 0x1ff);
+
+ fft_chn_idx = ((fft_summary_A >> 12) & 0x3);
+ peak_inx = fft_summary_A & 0xfff;
+
+ if (peak_inx > 2047)
+ peak_inx = peak_inx - 4096;
+
+ avgpwr_db = ((fft_summary_B >> 18) & 0xff);
+ peak_mag = ((fft_summary_B >> 8) & 0x3ff);
+
+ qdf_print("Header A = 0x%x Header B = 0x%x\n",
+ phdr->hdr_a, phdr->hdr_b);
+ qdf_print("Base Power= 0x%x, Total Gain= %d, relpwr_db=%d, "
+ "num_str_bins_ib=%d fft_chn_idx=%d peak_inx=%d avgpwr_db=%d "
+ "peak_mag=%d\n", base_pwr, total_gain_info, relpwr_db,
+ num_str_bins_ib, fft_chn_idx, peak_inx, avgpwr_db, peak_mag);
+ if (is_160_format) {
+ segid = fft_summary_C & 0x1;
+ qdf_print("Segment ID: %hhu\n", segid);
+ }
+
+ qdf_print("FFT bins:\n");
+ for (i = 0; i < (tlvlen - 8 - segid_skiplen); i++) {
+ fft_mag = ((u_int8_t *)ptlv)[12 + segid_skiplen + i];
+ qdf_print("%d %d, ", i, fft_mag);
+ }
+
+ qdf_print("\n");
+
+ return 0;
+}
+
+/*
+ * Function : spectral_process_phyerr_gen2
+ * Description : Process PHY Error
+ * Input : Pointer to buffer
+ * Output : Success/Failure
+ *
+ */
+int spectral_process_phyerr_gen2(
+ struct target_if_spectral *spectral,
+ u_int8_t *data,
+ u_int32_t datalen, struct target_if_spectral_rfqual_info *p_rfqual,
+ struct target_if_spectral_chan_info *p_chaninfo,
+ u_int64_t tsf64,
+ struct target_if_spectral_acs_stats *acs_stats)
+{
+ /*
+ * XXX : The classifier do not use all the members of the SAMP
+ * message data format.
+ * The classifier only depends upon the following parameters
+ *
+ * 1. Frequency (freq, msg->freq)
+ * 2. Spectral RSSI (spectral_rssi,
+ * msg->samp_data.spectral_rssi)
+ * 3. Bin Power Count (bin_pwr_count,
+ * msg->samp_data.bin_pwr_count)
+ * 4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
+ * 5. Spectral Timestamp (spectral_tstamp,
+ * msg->samp_data.spectral_tstamp)
+ * 6. MAC Address (macaddr, msg->macaddr)
+ *
+ * This function prepares the params structure and populates it
+ * with
+ * relevant values, this is in turn passed to
+ * spectral_create_samp_msg()
+ * to prepare fully formatted Spectral SAMP message
+ *
+ * XXX : Need to verify
+ * 1. Order of FFT bin values
+ *
+ */
+
+ struct target_if_samp_msg_params params;
+ SPECTRAL_SEARCH_FFT_INFO_GEN2 search_fft_info;
+ SPECTRAL_SEARCH_FFT_INFO_GEN2 *p_sfft = &search_fft_info;
+ SPECTRAL_SEARCH_FFT_INFO_GEN2 search_fft_info_sec80;
+ SPECTRAL_SEARCH_FFT_INFO_GEN2 *p_sfft_sec80 = &search_fft_info_sec80;
+ u_int32_t segid_skiplen = 0;
+
+ int8_t rssi_up = 0;
+ int8_t rssi_low = 0;
+
+ int8_t chn_idx_highest_enabled = 0;
+ int8_t chn_idx_lowest_enabled = 0;
+
+ u_int8_t control_rssi = 0;
+ u_int8_t extension_rssi = 0;
+ u_int8_t combined_rssi = 0;
+
+ u_int32_t tstamp = 0;
+
+ struct target_if_spectral_ops *p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+
+ SPECTRAL_PHYERR_TLV_GEN2 *ptlv = (SPECTRAL_PHYERR_TLV_GEN2 *)data;
+ SPECTRAL_PHYERR_TLV_GEN2 *ptlv_sec80 = NULL;
+ SPECTRAL_PHYERR_FFT_GEN2 *pfft = NULL;
+ SPECTRAL_PHYERR_FFT_GEN2 *pfft_sec80 = NULL;
+
+ u_int8_t segid = 0;
+ u_int8_t segid_sec80 = 0;
+
+ if (spectral->is_160_format)
+ segid_skiplen = sizeof(SPECTRAL_SEGID_INFO);
+
+ pfft = (SPECTRAL_PHYERR_FFT_GEN2 *)(data +
+ sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
+ sizeof(SPECTRAL_PHYERR_HDR_GEN2) + segid_skiplen);
+
+ /* XXX Extend SPECTRAL_DPRINTK() to use spectral_debug_level,
+ * and use this facility inside spectral_dump_phyerr_data()
+ * and supporting functions.
+ */
+ if (spectral_debug_level & ATH_DEBUG_SPECTRAL2)
+ spectral_dump_phyerr_data_gen2(data, datalen, spectral->is_160_format);
+
+ if (spectral_debug_level & ATH_DEBUG_SPECTRAL4) {
+ spectral_dump_phyerr_data_gen2(data, datalen, spectral->is_160_format);
+ spectral_debug_level = ATH_DEBUG_SPECTRAL;
+ }
+
+ if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
+ /* EV# 118023: We tentatively disable the below print
+ * and provide stats instead.
+ */
+ /* qdf_print("SPECTRAL : Mismatch\n"); */
+ spectral->diag_stats.spectral_mismatch++;
+ return -EPERM;
+ }
+
+ OS_MEMZERO(¶ms, sizeof(params));
+
+ if (ptlv->tag == TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
+ if (spectral->is_160_format) {
+ segid = *((SPECTRAL_SEGID_INFO *)(
+ (u_int8_t *)ptlv +
+ sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
+ sizeof(SPECTRAL_PHYERR_HDR_GEN2)));
+
+ if (segid != 0) {
+ spectral->diag_stats.spectral_vhtseg1id_mismatch++;
+ return -EPERM;
+ }
+ }
+
+ process_search_fft_report_gen2(ptlv, ptlv->length, &search_fft_info);
+
+ tstamp = p_sops->get_tsf64(spectral) & SPECTRAL_TSMASK;
+
+ combined_rssi = p_rfqual->rssi_comb;
+
+ if (spectral->upper_is_control)
+ rssi_up = control_rssi;
+ else
+ rssi_up = extension_rssi;
+
+ if (spectral->lower_is_control)
+ rssi_low = control_rssi;
+ else
+ rssi_low = extension_rssi;
+
+ params.rssi = p_rfqual->rssi_comb;
+ params.lower_rssi = rssi_low;
+ params.upper_rssi = rssi_up;
+
+ if (spectral->sc_spectral_noise_pwr_cal) {
+ params.chain_ctl_rssi[0] =
+ p_rfqual->pc_rssi_info[0].rssi_pri20;
+ params.chain_ctl_rssi[1] =
+ p_rfqual->pc_rssi_info[1].rssi_pri20;
+ params.chain_ctl_rssi[2] =
+ p_rfqual->pc_rssi_info[2].rssi_pri20;
+ params.chain_ext_rssi[0] =
+ p_rfqual->pc_rssi_info[0].rssi_sec20;
+ params.chain_ext_rssi[1] =
+ p_rfqual->pc_rssi_info[1].rssi_sec20;
+ params.chain_ext_rssi[2] =
+ p_rfqual->pc_rssi_info[2].rssi_sec20;
+ }
+
+ /*
+ * XXX : This actually depends on the programmed chain mask
+ * There are three chains in Peregrine and 4 chains in Beeliner &
+ * Cascade
+ * This value decides the per-chain enable mask to select
+ * the input ADC for search FTT.
+ * For modes upto VHT80, if more than one chain is enabled, the
+ * max valid chain
+ * is used. LSB corresponds to chain zero.
+ * For VHT80_80 and VHT160, the lowest enabled chain is used for
+ * primary
+ * detection and highest enabled chain is used for secondary
+ * detection.
+ *
+ * XXX: The current algorithm do not use these control and extension
+ * channel
+ * Instead, it just relies on the combined RSSI values only.
+ * For fool-proof detection algorithm, we should take these RSSI
+ * values
+ * in to account. This is marked for future enhancements.
+ */
+ chn_idx_highest_enabled = ((spectral->params.ss_chn_mask & 0x8) ? 3 :
+ (spectral->params.ss_chn_mask & 0x4) ? 2 :
+ (spectral->params.ss_chn_mask & 0x2) ? 1 : 0);
+ chn_idx_lowest_enabled = ((spectral->params.ss_chn_mask & 0x1) ? 0 :
+ (spectral->params.ss_chn_mask & 0x2) ? 1 :
+ (spectral->params.ss_chn_mask & 0x4) ? 2 : 3);
+ control_rssi = (u_int8_t)
+ p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
+ extension_rssi = (u_int8_t)
+ p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
+
+ params.bwinfo = 0;
+ params.tstamp = 0;
+ params.max_mag = p_sfft->peak_mag;
+
+ params.max_index = p_sfft->peak_inx;
+ params.max_exp = 0;
+ params.peak = 0;
+ params.bin_pwr_data = (u_int8_t *)pfft;
+ params.freq = p_sops->get_current_channel(spectral);
+ params.freq_loading = 0;
+
+ params.interf_list.count = 0;
+ params.max_lower_index = 0;
+ params.max_upper_index = 0;
+ params.nb_lower = 0;
+ params.nb_upper = 0;
+ /*
+ * For modes upto VHT80, the noise floor is populated with the one
+ * corresponding
+ * to the highest enabled antenna chain
+ */
+ params.noise_floor =
+ p_rfqual->noise_floor[chn_idx_highest_enabled];
+ params.datalen = ptlv->length;
+ params.pwr_count = ptlv->length -
+ sizeof(SPECTRAL_PHYERR_HDR_GEN2) - segid_skiplen;
+ params.tstamp = (tsf64 & SPECTRAL_TSMASK);
+
+ acs_stats->ctrl_nf = params.noise_floor;
+ acs_stats->ext_nf = params.noise_floor;
+ acs_stats->nfc_ctl_rssi = control_rssi;
+ acs_stats->nfc_ext_rssi = extension_rssi;
+
+ if (spectral->is_160_format &&
+ spectral->ch_width == IEEE80211_CWM_WIDTH160) {
+ /* We expect to see one more Search FFT report, and it should
+ * be equal in size to the current one.
+ */
+ if (datalen < (2 * (sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
+ ptlv->length))) {
+ spectral->diag_stats.spectral_sec80_sfft_insufflen++;
+ return -EPERM;
+ }
+
+ ptlv_sec80 = (SPECTRAL_PHYERR_TLV_GEN2 *)(
+ data +
+ sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
+ ptlv->length);
+
+ if (ptlv_sec80->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
+ spectral->diag_stats.spectral_mismatch++;
+ return -EPERM;
+ }
+
+ if (ptlv_sec80->tag != TLV_TAG_SEARCH_FFT_REPORT_GEN2) {
+ spectral->diag_stats.spectral_no_sec80_sfft++;
+ return -EPERM;
+ }
+
+ segid_sec80 = *((SPECTRAL_SEGID_INFO *)(
+ (u_int8_t *)ptlv_sec80 +
+ sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
+ sizeof(SPECTRAL_PHYERR_HDR_GEN2)));
+
+ if (segid_sec80 != 1) {
+ spectral->diag_stats.spectral_vhtseg2id_mismatch++;
+ return -EPERM;
+ }
+
+ params.vhtop_ch_freq_seg1 = p_chaninfo->center_freq1;
+ params.vhtop_ch_freq_seg2 = p_chaninfo->center_freq2;
+
+ process_search_fft_report_gen2(
+ ptlv_sec80,
+ ptlv_sec80->length, &search_fft_info_sec80);
+
+ pfft_sec80 = (SPECTRAL_PHYERR_FFT_GEN2 *)(
+ ((u_int8_t *)ptlv_sec80) +
+ sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
+ sizeof(SPECTRAL_PHYERR_HDR_GEN2) +
+ segid_skiplen);
+
+ /* XXX: Confirm. TBD at SoD. */
+ params.rssi_sec80 = p_rfqual->rssi_comb;
+ if (spectral->is_sec80_rssi_war_required)
+ params.rssi_sec80 =
+ get_combined_rssi_sec80_segment_gen2(
+ spectral,
+ &search_fft_info_sec80);
+ /* XXX: Determine dynamically. TBD at SoD. */
+ /*
+ * For VHT80_80/VHT160, the noise floor for primary 80MHz
+ * segment is populated with the
+ * lowest enabled antenna chain and the noise floor for
+ * secondary 80MHz segment is populated
+ * with the highest enabled antenna chain
+ */
+ params.noise_floor_sec80 =
+ p_rfqual->noise_floor[chn_idx_highest_enabled];
+ params.noise_floor =
+ p_rfqual->noise_floor[chn_idx_lowest_enabled];
+
+ params.max_mag_sec80 = p_sfft_sec80->peak_mag;
+ params.max_index_sec80 = p_sfft_sec80->peak_inx;
+ /* XXX Does this definition of datalen *still hold? */
+ params.datalen_sec80 = ptlv_sec80->length;
+ params.pwr_count_sec80 =
+ ptlv_sec80->length -
+ sizeof(SPECTRAL_PHYERR_HDR_GEN2) -
+ segid_skiplen;
+ params.bin_pwr_data_sec80 = (u_int8_t *)pfft_sec80;
+ }
+ qdf_mem_copy(
+ ¶ms.classifier_params,
+ &spectral->classifier_params,
+ sizeof(struct spectral_classifier_params));
+
+#ifdef SPECTRAL_DEBUG_SAMP_MSG
+ target_if_dbg_print_SAMP_param(¶ms);
+#endif
+ target_if_spectral_create_samp_msg(spectral, ¶ms);
+ }
+
+ return 0;
+}
+
+/*
+ * Function : spectral_dump_header_gen2
+ * Description : Dump Spectral header
+ * Input : Pointer to Spectral Phyerr Header
+ * Output : Success/Failure
+ *
+ */
+int spectral_dump_header_gen2(SPECTRAL_PHYERR_HDR_GEN2 *phdr)
+{
+ u_int32_t a = 0;
+ u_int32_t b = 0;
+
+ qdf_mem_copy(&a, (u_int8_t *)phdr, sizeof(int));
+ qdf_mem_copy(
+ &b,
+ (u_int8_t *)((u_int8_t *)phdr + sizeof(int)), sizeof(int));
+
+ qdf_print("SPECTRAL : HEADER A 0x%x (%d)\n", a, a);
+ qdf_print("SPECTRAL : HEADER B 0x%x (%d)\n", b, b);
+ return 0;
+}
+
+/*
+ * Function : get_combined_rssi_sec80_segment_gen2
+ * Description : Get approximate combined RSSI for Secondary 80 segment
+ * Input : Pointer to spectral and pointer to search fft info
+ * of secondary 80 segment
+ * Output : Combined RSSI for secondary 80Mhz segment
+ *
+ */
+int8_t get_combined_rssi_sec80_segment_gen2(
+ struct target_if_spectral *spectral,
+ SPECTRAL_SEARCH_FFT_INFO_GEN2 *p_sfft_sec80)
+{
+ uint32_t avgpwr_db = 0;
+ uint32_t total_gain_db = 0;
+ uint32_t offset = 0;
+ int8_t comb_rssi = 0;
+
+ /* Obtain required parameters for algorithm from search FFT report */
+ avgpwr_db = p_sfft_sec80->avgpwr_db;
+ total_gain_db = p_sfft_sec80->total_gain_info;
+
+ /* Calculate offset */
+ offset = target_if_get_offset_swar_sec80(spectral->ch_width);
+
+ /* Calculate RSSI */
+ comb_rssi = ((avgpwr_db - total_gain_db) + offset);
+
+ return comb_rssi;
+}
+
+/*
+ * Function : spectral_dump_tlv_gen2
+ * Description : Dump Spectral TLV
+ * Input : Pointer to Spectral Phyerr TLV, flag indicating whether
+ * information provided by HW is in altered format for 802.11ac
+ * 160/80+80 MHz support (QCA9984 onwards).
+ * Output : Success/Failure
+ *
+ */
+int spectral_dump_tlv_gen2(SPECTRAL_PHYERR_TLV_GEN2 *ptlv, bool is_160_format)
+{
+ int ret = 0;
+
+ /* TODO : Do not delete the following print
+ * The scripts used to validate Spectral depend on this Print
+ */
+ qdf_print("SPECTRAL : TLV Length is 0x%x (%d)\n",
+ ptlv->length, ptlv->length);
+
+ switch (ptlv->tag) {
+ case TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN2:
+ ret = dump_summary_report_gen2(
+ ptlv, ptlv->length, is_160_format);
+ break;
+
+ case TLV_TAG_SEARCH_FFT_REPORT_GEN2:
+ ret = dump_search_fft_report_gen2(
+ ptlv, ptlv->length, is_160_format);
+ break;
+
+ case TLV_TAG_ADC_REPORT_GEN2:
+ ret = dump_adc_report_gen2(
+ ptlv, ptlv->length);
+ break;
+
+ default:
+ qdf_print("SPECTRAL : INVALID TLV\n");
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+/*
+ * Function : spectral_dump_phyerr_data_gen2
+ * Description : Dump Spectral related PHY Error TLVs
+ * Input : Pointer to buffer, flag indicating whether information
+ * provided by HW is in altered format for 802.11ac 160/80+80 MHz
+ * support (QCA9984 onwards).
+ * Output : Success/Failure
+ *
+ */
+int spectral_dump_phyerr_data_gen2(u_int8_t *data, u_int32_t datalen,
+ bool is_160_format)
+{
+ SPECTRAL_PHYERR_TLV_GEN2 *ptlv = NULL;
+ u_int32_t bytes_processed = 0;
+ u_int32_t bytes_remaining = datalen;
+ u_int32_t curr_tlv_complete_size = 0;
+
+ if (datalen < sizeof(SPECTRAL_PHYERR_TLV_GEN2)) {
+ qdf_print("DRIVER: Total PHY error data length %u too short to contain"
+ " any TLVs\n", datalen);
+ return -EPERM;
+ }
+
+ while (bytes_processed < datalen) {
+ if (bytes_remaining < sizeof(SPECTRAL_PHYERR_TLV_GEN2)) {
+ qdf_print("DRIVER: Remaining PHY error data length %u too "
+ "short to contain a TLV\n", bytes_remaining);
+ return -EPERM;
+ }
+
+ ptlv = (SPECTRAL_PHYERR_TLV_GEN2 *)(data + bytes_processed);
+
+ if (ptlv->signature != SPECTRAL_PHYERR_SIGNATURE_GEN2) {
+ qdf_print("DRIVER : Invalid signature 0x%x!\n",
+ ptlv->signature);
+ return -EPERM;
+ }
+
+ curr_tlv_complete_size = sizeof(SPECTRAL_PHYERR_TLV_GEN2) +
+ ptlv->length;
+
+ if (curr_tlv_complete_size > bytes_remaining) {
+ qdf_print("DRIVER : Current indicated complete TLV size %u "
+ "greater than number of bytes remaining to be "
+ "processed %u",
+ curr_tlv_complete_size,
+ bytes_remaining);
+ return -EPERM;
+ }
+
+ if (spectral_dump_tlv_gen2(ptlv, is_160_format) == -1)
+ return -EPERM;
+
+ bytes_processed += curr_tlv_complete_size;
+ bytes_remaining = datalen - bytes_processed;
+ }
+
+ return 0;
+}
+
+/* END of spectral GEN II HW specific functions */
+
+/* START of spectral GEN III HW specific functions */
+
+/*
+ * Function : process_search_fft_report_gen3
+ * Description : Process Search FFT Report
+ * Input : Pointer to Spectral fft report and pointer to search fft info
+ * Output : Success/Failure
+ *
+ */
+int process_search_fft_report_gen3(
+ struct spectral_phyerr_fft_report_gen3 *p_fft_report,
+ struct spectral_search_fft_info_gen3 *p_sfft)
+{
+ /* For simplicity, everything is defined as uint32_t (except one).
+ * Proper code will later use the right sizes.
+ */
+ /* For easy comparision between MDK team and OS team, the MDK script
+ * variable names have been used
+ */
+ int32_t peak_sidx;
+ int32_t peak_mag;
+
+ /* Populate the Search FFT Info */
+ if (p_sfft) {
+ p_sfft->timestamp = p_fft_report->fft_timestamp;
+
+ p_sfft->fft_detector_id = get_bitfield(
+ p_fft_report->hdr_a,
+ 2,
+ 0);
+ p_sfft->fft_num = get_bitfield(
+ p_fft_report->hdr_a,
+ 3,
+ 2);
+ p_sfft->fft_radar_check = get_bitfield(
+ p_fft_report->hdr_a,
+ 12,
+ 5);
+
+ peak_sidx = get_bitfield(
+ p_fft_report->hdr_a,
+ 11,
+ 17);
+ p_sfft->fft_peak_sidx = unsigned_to_signed(peak_sidx, 11);
+ p_sfft->fft_chn_idx = get_bitfield(
+ p_fft_report->hdr_a,
+ 3,
+ 28);
+
+ p_sfft->fft_base_pwr_db = get_bitfield(
+ p_fft_report->hdr_b,
+ 9,
+ 0);
+ p_sfft->fft_total_gain_db = get_bitfield(
+ p_fft_report->hdr_b,
+ 8,
+ 9);
+
+ p_sfft->fft_num_str_bins_ib = get_bitfield(
+ p_fft_report->hdr_c,
+ 8,
+ 0);
+ peak_mag = get_bitfield(
+ p_fft_report->hdr_c,
+ 10,
+ 8);
+ p_sfft->fft_peak_mag = unsigned_to_signed(peak_mag, 10);
+ p_sfft->fft_avgpwr_db = get_bitfield(
+ p_fft_report->hdr_c,
+ 7,
+ 18);
+ p_sfft->fft_relpwr_db = get_bitfield(
+ p_fft_report->hdr_c,
+ 7,
+ 25);
+ }
+
+ return 0;
+}
+
+/*
+ * Function : spectral_dump_fft_report_gen3
+ * Description : Process Search FFT Report
+ * Input : Pointer to Spectral fft report and pointer to search fft info
+ * Output : Success/Failure
+ *
+ */
+int spectral_dump_fft_report_gen3(
+ struct spectral_phyerr_fft_report_gen3 *p_fft_report,
+ struct spectral_search_fft_info_gen3 *p_sfft)
+{
+ int i = 0;
+ int fft_mag = 0;
+ int fft_hdr_length = (p_fft_report->fft_hdr_length * 4);
+ int report_len = (fft_hdr_length + 8);
+ int fft_bin_len = (fft_hdr_length - 16);
+
+ qdf_print("##############################################"
+ "###############\n");
+ qdf_print("Spectral search fft_report\n");
+ qdf_print("fft_timestamp = 0x%x\n"
+ "fft_hdr_length = %d(32 bit words)\n"
+ "fft_hdr_tag = 0x%x\n"
+ "fft_hdr_sig = 0x%x\n",
+ p_fft_report->fft_timestamp,
+ p_fft_report->fft_hdr_length,
+ p_fft_report->fft_hdr_tag,
+ p_fft_report->fft_hdr_sig);
+
+ qdf_print("Length field in search fft report is %d(0x%x) bytes\n",
+ fft_hdr_length, fft_hdr_length);
+ qdf_print("Total length of search fft report is %d(0x%x) bytes\n",
+ report_len, report_len);
+ qdf_print("Number of fftbins in report is %d(0x%x)\n", fft_bin_len,
+ fft_bin_len);
+
+ qdf_print("fft_detector_id = %u\n"
+ "fft_num = %u\n"
+ "fft_radar_check = %u\n"
+ "fft_peak_sidx = %d\n"
+ "fft_chn_idx = %u\n"
+ "fft_base_pwr_db = %u\n"
+ "fft_total_gain_db = %u\n"
+ "fft_num_str_bins_ib = %u\n"
+ "fft_peak_mag = %d\n"
+ "fft_avgpwr_db = %u\n"
+ "fft_relpwr_db = %u\n",
+ p_sfft->fft_detector_id,
+ p_sfft->fft_num,
+ p_sfft->fft_radar_check,
+ p_sfft->fft_peak_sidx,
+ p_sfft->fft_chn_idx,
+ p_sfft->fft_base_pwr_db,
+ p_sfft->fft_total_gain_db,
+ p_sfft->fft_num_str_bins_ib,
+ p_sfft->fft_peak_mag,
+ p_sfft->fft_avgpwr_db,
+ p_sfft->fft_relpwr_db);
+
+ qdf_print("FFT bins:\n");
+ for (i = 0; i < (fft_hdr_length - 16); i++) {
+ fft_mag = ((u_int8_t *)p_fft_report)[SPECTRAL_FFT_BINS_POS + i];
+ qdf_print("%d: %d, ", i, fft_mag);
+ if (i % 16 == 0)
+ qdf_print("\n");
+ }
+ qdf_print("\n");
+ qdf_print("###########################################################"
+ "##\n");
+
+ return 0;
+}
+
+int consume_searchfft_report_gen3(
+ struct target_if_spectral *spectral,
+ struct phyerr_info *pinfo)
+{
+ /*
+ * XXX : The classifier do not use all the members of the SAMP
+ * message data format.
+ * The classifier only depends upon the following parameters
+ *
+ * 1. Frequency (freq, msg->freq)
+ * 2. Spectral RSSI (spectral_rssi,
+ * msg->samp_data.spectral_rssi)
+ * 3. Bin Power Count (bin_pwr_count,
+ * msg->samp_data.bin_pwr_count)
+ * 4. Bin Power values (bin_pwr, msg->samp_data.bin_pwr[0]
+ * 5. Spectral Timestamp (spectral_tstamp,
+ * msg->samp_data.spectral_tstamp)
+ * 6. MAC Address (macaddr, msg->macaddr)
+ *
+ * This function prepares the params structure and populates it
+ * with
+ * relevant values, this is in turn passed to
+ * spectral_create_samp_msg()
+ * to prepare fully formatted Spectral SAMP message
+ *
+ * XXX : Need to verify
+ * 1. Order of FFT bin values
+ *
+ */
+
+ /* Unpack the arguments */
+ u_int32_t datalen = pinfo->datalen;
+ struct target_if_spectral_rfqual_info *p_rfqual = pinfo->p_rfqual;
+ struct target_if_spectral_chan_info *p_chaninfo = pinfo->p_chaninfo;
+ u_int64_t tsf64 = pinfo->tsf64;
+ struct target_if_spectral_acs_stats *acs_stats = pinfo->acs_stats;
+
+ struct target_if_samp_msg_params params;
+ struct spectral_search_fft_info_gen3 search_fft_info;
+ struct spectral_search_fft_info_gen3 *p_sfft = &search_fft_info;
+ int8_t rssi_up = 0;
+ int8_t rssi_low = 0;
+ int8_t chn_idx_highest_enabled = 0;
+ int8_t chn_idx_lowest_enabled = 0;
+ u_int8_t control_rssi = 0;
+ u_int8_t extension_rssi = 0;
+ u_int32_t tstamp = 0;
+ int fft_hdr_length = 0;
+ int report_len = 0;
+ int fft_bin_len = 0;
+ struct target_if_spectral_ops *p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+ struct spectral_phyerr_fft_report_gen3 *p_fft_report =
+ (struct spectral_phyerr_fft_report_gen3 *)(pinfo->data);
+
+ OS_MEMZERO(¶ms, sizeof(params));
+
+ fft_hdr_length = p_fft_report->fft_hdr_length * 4;
+ if (fft_hdr_length < 16) {
+ qdf_print("SPECTRAL : Unexpected TLV length %u for FFT Report! Hexdump"
+ " follows\n", fft_hdr_length);
+ goto fail;
+ }
+
+ report_len = (fft_hdr_length + 8);
+ fft_bin_len = (fft_hdr_length - 16);
+ if (datalen < report_len) {
+ qdf_print("DRIVER: Total PHY error data length %u too short to"
+ " contain the search fft report of length %u\n",
+ datalen, report_len);
+ goto fail;
+ }
+
+ process_search_fft_report_gen3(p_fft_report, p_sfft);
+
+ if (p_sfft->fft_detector_id != 0) {
+ qdf_print("Expected segid is 0 but we got %d\n",
+ p_sfft->fft_detector_id);
+ spectral->diag_stats.spectral_vhtseg1id_mismatch++;
+ goto fail;
+ }
+
+ if (spectral_debug_level & (ATH_DEBUG_SPECTRAL2 | ATH_DEBUG_SPECTRAL4))
+ spectral_dump_fft_report_gen3(p_fft_report, p_sfft);
+
+ tstamp = p_sops->get_tsf64(spectral) & SPECTRAL_TSMASK;
+
+ if (spectral->upper_is_control)
+ rssi_up = control_rssi;
+ else
+ rssi_up = extension_rssi;
+
+ if (spectral->lower_is_control)
+ rssi_low = control_rssi;
+ else
+ rssi_low = extension_rssi;
+
+ params.rssi = p_rfqual->rssi_comb;
+ params.lower_rssi = rssi_low;
+ params.upper_rssi = rssi_up;
+
+ if (spectral->sc_spectral_noise_pwr_cal) {
+ /* qdf_print("SPECTRAL : Needs to verified with FW\n"); */
+ params.chain_ctl_rssi[0] = p_rfqual->pc_rssi_info[0].rssi_pri20;
+ params.chain_ctl_rssi[1] = p_rfqual->pc_rssi_info[1].rssi_pri20;
+ params.chain_ctl_rssi[2] = p_rfqual->pc_rssi_info[2].rssi_pri20;
+ params.chain_ext_rssi[0] = p_rfqual->pc_rssi_info[0].rssi_sec20;
+ params.chain_ext_rssi[1] = p_rfqual->pc_rssi_info[1].rssi_sec20;
+ params.chain_ext_rssi[2] = p_rfqual->pc_rssi_info[2].rssi_sec20;
+ }
+
+ /*
+ * XXX : This actually depends on the programmed chain mask
+ * There are three chains in Peregrine and 4 chains in Beeliner &
+ * Cascade
+ * This value decides the per-chain enable mask to select
+ * the input ADC for search FTT.
+ * For modes upto VHT80, if more than one chain is enabled, the
+ * max valid chain
+ * is used. LSB corresponds to chain zero.
+ * For VHT80_80 and VHT160, the lowest enabled chain is used for
+ * primary
+ * detection and highest enabled chain is used for secondary
+ * detection.
+ *
+ * XXX: The current algorithm do not use these control and extension
+ * channel
+ * Instead, it just relies on the combined RSSI values only.
+ * For fool-proof detection algorithm, we should take these RSSI
+ * values
+ * in to account. This is marked for future enhancements.
+ */
+ /* qdf_print("SPECTRAL : TBD (Chainmask changes for 8x8)\n"); */
+ chn_idx_highest_enabled = ((spectral->params.ss_chn_mask & 0x8) ? 3 :
+ (spectral->params.ss_chn_mask & 0x4) ? 2 :
+ (spectral->params.ss_chn_mask & 0x2) ? 1 : 0);
+ chn_idx_lowest_enabled = ((spectral->params.ss_chn_mask & 0x1) ? 0 :
+ (spectral->params.ss_chn_mask & 0x2) ? 1 :
+ (spectral->params.ss_chn_mask & 0x4) ? 2 : 3);
+ control_rssi = (u_int8_t)
+ p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_pri20;
+ extension_rssi = (u_int8_t)
+ p_rfqual->pc_rssi_info[chn_idx_highest_enabled].rssi_sec20;
+
+ params.bwinfo = 0;
+ params.tstamp = 0;
+ params.max_mag = p_sfft->fft_peak_mag;
+
+ /* params.max_index = p_sfft->peak_inx; */
+ params.max_exp = 0;
+ params.peak = 0;
+ params.bin_pwr_data = (u_int8_t *)((uint8_t *)p_fft_report +
+ SPECTRAL_FFT_BINS_POS);
+ params.freq = p_sops->get_current_channel(spectral);
+ params.freq_loading = 0;
+
+ params.interf_list.count = 0;
+ params.max_lower_index = 0;
+ params.max_upper_index = 0;
+ params.nb_lower = 0;
+ params.nb_upper = 0;
+ /*
+ * For modes upto VHT80, the noise floor is populated with the one
+ * corresponding
+ * to the highest enabled antenna chain
+ */
+ params.noise_floor =
+ p_rfqual->noise_floor[chn_idx_highest_enabled];
+ params.datalen = (fft_hdr_length * 4);
+ params.pwr_count = fft_bin_len;
+ params.tstamp = (tsf64 & SPECTRAL_TSMASK);
+
+ acs_stats->ctrl_nf = params.noise_floor;
+ acs_stats->ext_nf = params.noise_floor;
+ acs_stats->nfc_ctl_rssi = control_rssi;
+ acs_stats->nfc_ext_rssi = extension_rssi;
+
+ if (spectral->ch_width == IEEE80211_CWM_WIDTH160) {
+ /* We expect to see one more Search FFT report, and it should be
+ * equal in size to the current one.
+ */
+ if (datalen != (2 * report_len)) {
+ spectral->diag_stats.spectral_sec80_sfft_insufflen++;
+ goto fail;
+ }
+
+ p_fft_report = (struct spectral_phyerr_fft_report_gen3 *)(
+ (uint8_t *)p_fft_report + report_len);
+
+ if (p_fft_report->fft_hdr_sig != SPECTRAL_PHYERR_SIGNATURE_GEN3) {
+ spectral->diag_stats.spectral_mismatch++;
+ goto fail;
+ }
+
+ if (p_fft_report->fft_hdr_tag != TLV_TAG_SEARCH_FFT_REPORT_GEN3) {
+ spectral->diag_stats.spectral_no_sec80_sfft++;
+ goto fail;
+ }
+
+ fft_hdr_length = p_fft_report->fft_hdr_length * 4;
+ report_len = (fft_hdr_length + 8);
+ fft_bin_len = (fft_hdr_length - 16);
+
+ process_search_fft_report_gen3(p_fft_report, p_sfft);
+
+ if (p_sfft->fft_detector_id != 1) {
+ qdf_print("Expected segid is 1 but we got %d\n",
+ p_sfft->fft_detector_id);
+ spectral->diag_stats.spectral_vhtseg2id_mismatch++;
+ goto fail;
+ }
+
+ if (spectral_debug_level & (ATH_DEBUG_SPECTRAL2 | ATH_DEBUG_SPECTRAL4))
+ spectral_dump_fft_report_gen3(p_fft_report, p_sfft);
+
+ params.vhtop_ch_freq_seg1 = p_chaninfo->center_freq1;
+ params.vhtop_ch_freq_seg2 = p_chaninfo->center_freq2;
+
+ /* XXX: Confirm. TBD at SoD. */
+ params.rssi_sec80 = p_rfqual->rssi_comb;
+
+ /* if (spectral->is_sec80_rssi_war_required) { */
+ /* params.rssi_sec80 = get_combined_rssi_sec80_segment_gen3(spectral,
+ * &search_fft_info_sec80);
+ */
+ /* } */
+ /* XXX: Determine dynamically. TBD at SoD. */
+
+ /*
+ * For VHT80_80/VHT160, the noise floor for primary 80MHz segment is
+ * populated with the
+ * lowest enabled antenna chain and the noise floor for secondary 80MHz
+ * segment is populated
+ * with the highest enabled antenna chain
+ */
+ params.noise_floor_sec80 =
+ p_rfqual->noise_floor[chn_idx_highest_enabled];
+ params.noise_floor =
+ p_rfqual->noise_floor[chn_idx_lowest_enabled];
+
+ params.max_mag_sec80 = p_sfft->fft_peak_mag;
+ /* params.max_index_sec80 = p_sfft->peak_inx; */
+ /* XXX Does this definition of datalen *still hold? */
+ params.datalen_sec80 = fft_hdr_length;
+ params.pwr_count_sec80 = fft_bin_len;
+ params.bin_pwr_data_sec80 = (u_int8_t *)(
+ (uint8_t *)p_fft_report + SPECTRAL_FFT_BINS_POS);
+ }
+
+ qdf_mem_copy(
+ ¶ms.classifier_params,
+ &spectral->classifier_params,
+ sizeof(struct spectral_classifier_params));
+#ifdef SPECTRAL_DEBUG_SAMP_MSG
+ target_if_dbg_print_SAMP_param(¶ms);
+#endif
+ target_if_spectral_create_samp_msg(spectral, ¶ms);
+
+ return 0;
+
+fail:
+ qdf_print("Error in function %s while processing search fft report\n",
+ __func__);
+ print_buf((uint8_t *)p_fft_report, fft_hdr_length + 8);
+ return -EPERM;
+}
+
+/*
+ * Function : spectral_process_phyerr_gen3
+ * Descrip_tion : Process PHY Error
+ * Input : Pointer to buffer
+ * Output : Success/Failure
+ *
+ */
+int spectral_process_phyerr_gen3(
+ struct target_if_spectral *spectral,
+ u_int8_t *data,
+ u_int32_t datalen, struct target_if_spectral_rfqual_info *p_rfqual,
+ struct target_if_spectral_chan_info *p_chaninfo,
+ u_int64_t tsf64,
+ struct target_if_spectral_acs_stats *acs_stats)
+{
+ uint8_t tag = 0;
+ uint8_t signature = 0;
+ struct phyerr_info pinfo;
+ int ret = 0;
+
+ /* pack arguments in a structure as there are
+ * more than 3 arguments
+ */
+ pinfo.data = data;
+ pinfo.datalen = datalen;
+ pinfo.p_rfqual = p_rfqual;
+ pinfo.p_chaninfo = p_chaninfo;
+ pinfo.tsf64 = tsf64;
+ pinfo.acs_stats = acs_stats;
+
+ if (spectral_debug_level &
+ (ATH_DEBUG_SPECTRAL2 | ATH_DEBUG_SPECTRAL4)) {
+ qdf_print("Printing the spectral phyerr buffer for debug "
+ "purpose\n");
+ qdf_print("Dalalength of buffer = 0x%x(%d)\n",
+ datalen, datalen);
+ RAWSIM_PKT_HEXDUMP(data, datalen);
+ }
+
+ /* Peek into the data to figure out whether
+ * 1) Signature matches the expected value
+ * 2) What is inside the package (TAG ID is used for finding this)
+ */
+ tag = *(data + PHYERR_HDR_TAG_POS);
+ signature = *(data + PHYERR_HDR_SIG_POS);
+
+ if (signature != SPECTRAL_PHYERR_SIGNATURE_GEN3) {
+ qdf_print("Unexpected signature %x in spectral phyerror "
+ "event\n", signature);
+ spectral->diag_stats.spectral_mismatch++;
+ ret = -1;
+ goto end;
+ }
+
+ switch (tag) {
+ case TLV_TAG_SPECTRAL_SUMMARY_REPORT_GEN3:
+ /* Place holder
+ * We don't use spectral scan report as of now
+ */
+ break;
+
+ case TLV_TAG_SEARCH_FFT_REPORT_GEN3:
+ ret = consume_searchfft_report_gen3(spectral, &pinfo);
+ break;
+
+ default:
+ qdf_print("Unknown tag %x in spectral phyerror event\n", tag);
+ break;
+ }
+
+end:
+ if (spectral_debug_level & ATH_DEBUG_SPECTRAL4)
+ spectral_debug_level = ATH_DEBUG_SPECTRAL;
+ return ret;
+}
+
+/* END of spectral GEN III HW specific functions */
+
+#endif /* WLAN_SPECTRAL_ENABLE */
diff --git a/target_if/spectral/target_if_spectral_sim.c b/target_if/spectral/target_if_spectral_sim.c
new file mode 100644
index 0000000..e71e3b1
--- /dev/null
+++ b/target_if/spectral/target_if_spectral_sim.c
@@ -0,0 +1,958 @@
+/*
+ * Copyright (c) 2015,2017 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.
+ */
+
+#if QCA_SUPPORT_SPECTRAL_SIMULATION
+#include "target_if_spectral.h"
+#include "target_if_spectral_sim.h"
+#include "target_if_spectral_sim_int.h"
+#include "_ieee80211.h"
+#include "ieee80211_api.h"
+#include "ieee80211_defines.h"
+#include "qdf_types.h"
+#include "ieee80211_var.h"
+#include <wlan_mlme_dispatcher.h>
+
+/* Helper functions */
+
+int tif_populate_reportset_fromfile(ath_spectralsim_reportset * reportset,
+ enum phy_ch_width width,
+ bool is_80_80);
+static int populate_report_static_gen2(ath_spectralsim_report *report,
+ enum phy_ch_width width,
+ bool is_80_80);
+static int populate_report_static_gen3(ath_spectralsim_report *report,
+ enum phy_ch_width width,
+ bool is_80_80);
+static void depopulate_report(ath_spectralsim_report *report);
+
+static int populate_reportset_static(ath_spectralsim_context *simctx,
+ ath_spectralsim_reportset *reportset,
+ enum phy_ch_width width,
+ bool is_80_80);
+static void depopulate_reportset(ath_spectralsim_reportset *reportset);
+
+static int populate_simdata(ath_spectralsim_context *simctx);
+static void depopulate_simdata(ath_spectralsim_context *simctx);
+static OS_TIMER_FUNC(spectral_sim_phyerrdelivery_handler);
+
+/* Static configuration.
+ * For now, we will be having a single configuration per BW, and a single
+ * report per configuration (since we need the data only for ensuring correct
+ * format handling).
+ *
+ * Extend this for more functionality if required in the future.
+ */
+
+/* Statically populate simulation data for one report. */
+static int populate_report_static_gen2(ath_spectralsim_report *report,
+ enum phy_ch_width width,
+ bool is_80_80)
+{
+ qdf_assert_always(report);
+
+ switch (width) {
+ case CH_WIDTH_20MHZ:
+ report->data = NULL;
+ report->data = (u_int8_t *)
+ qdf_mem_malloc(sizeof(reportdata_20_gen2));
+
+ if (!report->data) {
+ qdf_print("Spectral simulation: Could not allocate memory for "
+ "report data\n");
+ goto bad;
+ }
+
+ report->datasize = sizeof(reportdata_20_gen2);
+ qdf_mem_copy(report->data,
+ reportdata_20_gen2, report->datasize);
+
+ qdf_mem_copy(&report->rfqual_info,
+ &rfqual_info_20, sizeof(report->rfqual_info));
+
+ qdf_mem_copy(&report->chan_info,
+ &chan_info_20, sizeof(report->chan_info));
+
+ break;
+ case CH_WIDTH_40MHZ:
+ report->data = NULL;
+ report->data = (u_int8_t *)
+ qdf_mem_malloc(sizeof(reportdata_40_gen2));
+
+ if (!report->data) {
+ qdf_print("Spectral simulation: Could not allocate memory for "
+ "report data\n");
+ goto bad;
+ }
+
+ report->datasize = sizeof(reportdata_40_gen2);
+ qdf_mem_copy(report->data,
+ reportdata_40_gen2, report->datasize);
+
+ qdf_mem_copy(&report->rfqual_info,
+ &rfqual_info_40, sizeof(report->rfqual_info));
+
+ qdf_mem_copy(&report->chan_info,
+ &chan_info_40, sizeof(report->chan_info));
+
+ break;
+ case CH_WIDTH_80MHZ:
+ report->data = NULL;
+ report->data = (u_int8_t *)
+ qdf_mem_malloc(sizeof(reportdata_80_gen2));
+
+ if (!report->data) {
+ qdf_print("Spectral simulation: Could not allocate memory for "
+ "report data\n");
+ goto bad;
+ }
+
+ report->datasize = sizeof(reportdata_80_gen2);
+ qdf_mem_copy(report->data,
+ reportdata_80_gen2, report->datasize);
+
+ qdf_mem_copy(&report->rfqual_info,
+ &rfqual_info_80, sizeof(report->rfqual_info));
+
+ qdf_mem_copy(&report->chan_info,
+ &chan_info_80, sizeof(report->chan_info));
+
+ break;
+ case CH_WIDTH_160MHZ:
+ if (is_80_80) {
+ report->data = NULL;
+ report->data = (u_int8_t *)
+ qdf_mem_malloc(sizeof(reportdata_80_80_gen2));
+
+ if (!report->data) {
+ qdf_print("Spectral simulation: Could not allocate "
+ "memory for report data\n");
+ goto bad;
+ }
+
+ report->datasize = sizeof(reportdata_80_80_gen2);
+ qdf_mem_copy(report->data,
+ reportdata_80_80_gen2, report->datasize);
+
+ qdf_mem_copy(&report->rfqual_info,
+ &rfqual_info_80_80, sizeof(report->rfqual_info));
+
+ qdf_mem_copy(&report->chan_info,
+ &chan_info_80_80, sizeof(report->chan_info));
+
+ } else {
+ report->data = NULL;
+ report->data = (u_int8_t *)
+ qdf_mem_malloc(sizeof(reportdata_160_gen2));
+
+ if (!report->data) {
+ qdf_print("Spectral simulation: Could not allocate "
+ "memory for report data\n");
+ goto bad;
+ }
+
+ report->datasize = sizeof(reportdata_160_gen2);
+ qdf_mem_copy(report->data,
+ reportdata_160_gen2, report->datasize);
+
+ qdf_mem_copy(&report->rfqual_info,
+ &rfqual_info_160, sizeof(report->rfqual_info));
+
+ qdf_mem_copy(&report->chan_info,
+ &chan_info_160, sizeof(report->chan_info));
+ }
+ break;
+ default:
+ qdf_print("Unhandled width. Please correct. Asserting\n");
+ qdf_assert_always(0);
+ }
+
+ return 0;
+
+bad:
+ return -EPERM;
+}
+
+/* Statically populate simulation data for one report. */
+static int populate_report_static_gen3(ath_spectralsim_report *report,
+ enum phy_ch_width width,
+ bool is_80_80)
+{
+ qdf_assert_always(report);
+
+ switch (width) {
+ case CH_WIDTH_20MHZ:
+ report->data = NULL;
+ report->data = (u_int8_t *)
+ qdf_mem_malloc(sizeof(reportdata_20_gen3));
+
+ if (!report->data) {
+ qdf_print("Spectral simulation: Could not allocate "
+ "memory for report data\n");
+ goto bad;
+ }
+
+ report->datasize = sizeof(reportdata_20_gen3);
+ qdf_mem_copy(report->data,
+ reportdata_20_gen3, report->datasize);
+
+ qdf_mem_copy(&report->rfqual_info,
+ &rfqual_info_20, sizeof(report->rfqual_info));
+
+ qdf_mem_copy(&report->chan_info,
+ &chan_info_20, sizeof(report->chan_info));
+
+ break;
+ case CH_WIDTH_40MHZ:
+ report->data = NULL;
+ report->data = (u_int8_t *)
+ qdf_mem_malloc(sizeof(reportdata_40_gen3));
+
+ if (!report->data) {
+ qdf_print("Spectral simulation: Could not allocate "
+ "memory for report data\n");
+ goto bad;
+ }
+
+ report->datasize = sizeof(reportdata_40_gen3);
+ qdf_mem_copy(report->data,
+ reportdata_40_gen3, report->datasize);
+
+ qdf_mem_copy(&report->rfqual_info,
+ &rfqual_info_40, sizeof(report->rfqual_info));
+
+ qdf_mem_copy(&report->chan_info,
+ &chan_info_40, sizeof(report->chan_info));
+
+ break;
+ case CH_WIDTH_80MHZ:
+ report->data = NULL;
+ report->data = (u_int8_t *)
+ qdf_mem_malloc(sizeof(reportdata_80_gen3));
+
+ if (!report->data) {
+ qdf_print("Spectral simulation: Could not allocate memory for "
+ "report data\n");
+ goto bad;
+ }
+
+ report->datasize = sizeof(reportdata_80_gen3);
+ qdf_mem_copy(report->data,
+ reportdata_80_gen3, report->datasize);
+
+ qdf_mem_copy(&report->rfqual_info,
+ &rfqual_info_80, sizeof(report->rfqual_info));
+
+ qdf_mem_copy(&report->chan_info,
+ &chan_info_80, sizeof(report->chan_info));
+
+ break;
+ case CH_WIDTH_160MHZ:
+ if (is_80_80) {
+ report->data = NULL;
+ report->data = (u_int8_t *)
+ qdf_mem_malloc(sizeof(reportdata_80_80_gen3));
+
+ if (!report->data) {
+ qdf_print("Spectral simulation: Could not allocate "
+ "memory for report data\n");
+ goto bad;
+ }
+
+ report->datasize = sizeof(reportdata_80_80_gen3);
+ qdf_mem_copy(report->data,
+ reportdata_80_80_gen3, report->datasize);
+
+ qdf_mem_copy(&report->rfqual_info,
+ &rfqual_info_80_80, sizeof(report->rfqual_info));
+
+ qdf_mem_copy(&report->chan_info,
+ &chan_info_80_80, sizeof(report->chan_info));
+
+ } else {
+ report->data = NULL;
+ report->data = (u_int8_t *)
+ qdf_mem_malloc(sizeof(reportdata_160_gen3));
+
+ if (!report->data) {
+ qdf_print("Spectral simulation: Could not allocate "
+ "memory for report data\n");
+ goto bad;
+ }
+
+ report->datasize = sizeof(reportdata_160_gen3);
+ qdf_mem_copy(report->data,
+ reportdata_160_gen3, report->datasize);
+
+ qdf_mem_copy(&report->rfqual_info,
+ &rfqual_info_160, sizeof(report->rfqual_info));
+
+ qdf_mem_copy(&report->chan_info,
+ &chan_info_160, sizeof(report->chan_info));
+ }
+ break;
+ default:
+ qdf_print("Unhandled width. Please correct. Asserting\n");
+ qdf_assert_always(0);
+ }
+
+ return 0;
+
+bad:
+ return -EPERM;
+}
+
+static void depopulate_report(ath_spectralsim_report *report)
+{
+ if (!report)
+ return;
+
+ if (report->data) {
+ qdf_mem_free(report->data);
+ report->data = NULL;
+ report->datasize = 0;
+ }
+}
+
+/* Statically populate simulation data for a given configuration. */
+static int populate_reportset_static(ath_spectralsim_context *simctx,
+ ath_spectralsim_reportset *reportset,
+ enum phy_ch_width width,
+ bool is_80_80)
+{
+ int ret = 0;
+ ath_spectralsim_report *report = NULL;
+
+ qdf_assert_always(reportset);
+
+ reportset->headreport = NULL;
+ reportset->curr_report = NULL;
+
+ /* For now, we populate only one report */
+ report = (ath_spectralsim_report *)
+ qdf_mem_malloc(sizeof(ath_spectralsim_report));
+
+ if (!report) {
+ qdf_print("Spectral simulation: Could not allocate memory "
+ "for report.\n");
+ goto bad;
+ }
+
+ qdf_mem_zero(report, sizeof(*report));
+
+ switch (width) {
+ case CH_WIDTH_20MHZ:
+ qdf_mem_copy(&reportset->config,
+ &config_20_1, sizeof(reportset->config));
+
+ ret = simctx->populate_report_static(report, CH_WIDTH_20MHZ, 0);
+ if (ret != 0)
+ goto bad;
+
+ report->next = NULL;
+ reportset->headreport = report;
+ break;
+ case CH_WIDTH_40MHZ:
+ qdf_mem_copy(&reportset->config,
+ &config_40_1, sizeof(reportset->config));
+
+ ret = simctx->populate_report_static(report, CH_WIDTH_40MHZ, 0);
+ if (ret != 0)
+ goto bad;
+
+ report->next = NULL;
+ reportset->headreport = report;
+ break;
+ case CH_WIDTH_80MHZ:
+ qdf_mem_copy(&reportset->config,
+ &config_80_1, sizeof(reportset->config));
+
+ ret = simctx->populate_report_static(report, CH_WIDTH_80MHZ, 0);
+ if (ret != 0)
+ goto bad;
+
+ report->next = NULL;
+ reportset->headreport = report;
+ break;
+ case CH_WIDTH_160MHZ:
+ if (is_80_80) {
+ qdf_mem_copy(&reportset->config,
+ &config_80_80_1, sizeof(reportset->config));
+
+ ret = simctx->populate_report_static(
+ report,
+ CH_WIDTH_160MHZ,
+ 1);
+ if (ret != 0)
+ goto bad;
+
+ report->next = NULL;
+ reportset->headreport = report;
+ } else {
+ qdf_mem_copy(&reportset->config,
+ &config_160_1, sizeof(reportset->config));
+
+ ret = simctx->populate_report_static(
+ report,
+ CH_WIDTH_160MHZ,
+ 0);
+ if (ret != 0)
+ goto bad;
+
+ report->next = NULL;
+ reportset->headreport = report;
+ }
+ break;
+ default:
+ qdf_print("Unhandled width. Please rectify.\n");
+ qdf_assert_always(0);
+ };
+
+ reportset->curr_report = reportset->headreport;
+
+ return 0;
+
+bad:
+ depopulate_reportset(reportset);
+ return -EPERM;
+}
+
+static void depopulate_reportset(ath_spectralsim_reportset *reportset)
+{
+ ath_spectralsim_report *curr_report = NULL;
+ ath_spectralsim_report *next_report = NULL;
+
+ if (!reportset)
+ return;
+
+ curr_report = reportset->headreport;
+
+ while (curr_report) {
+ next_report = curr_report->next;
+ depopulate_report(curr_report);
+ qdf_mem_free(curr_report);
+ curr_report = next_report;
+ }
+}
+
+/* Populate simulation data for a given bandwidth by loading from a file.
+ * This is a place-holder only. To be implemented in the future on a need
+ * basis.
+ *
+ * A different file per bandwidth is suggested for better segregation of data
+ * sets (since data is likely to be very different across BWs).
+ */
+int tif_populate_reportset_fromfile(ath_spectralsim_reportset *reportset,
+ enum phy_ch_width width,
+ bool is_80_80)
+{
+ qdf_print("%s: To be implemented if required\n", __func__);
+
+ return 0;
+}
+
+/* Populate simulation data */
+static int populate_simdata(ath_spectralsim_context *simctx)
+{
+ /* For now, we use static population. Switch to loading from a file if
+ * needed in the future.
+ */
+
+ simctx->bw20_headreportset = NULL;
+ SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx,
+ simctx->bw20_headreportset,
+ CH_WIDTH_20MHZ,
+ 0);
+
+ simctx->bw40_headreportset = NULL;
+ SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx,
+ simctx->bw40_headreportset,
+ CH_WIDTH_40MHZ,
+ 0);
+
+ simctx->bw80_headreportset = NULL;
+ SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx,
+ simctx->bw80_headreportset,
+ CH_WIDTH_80MHZ,
+ 0);
+
+ simctx->bw160_headreportset = NULL;
+ SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx,
+ simctx->bw160_headreportset,
+ CH_WIDTH_160MHZ,
+ 0);
+
+ simctx->bw80_80_headreportset = NULL;
+ SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx,
+ simctx->bw80_80_headreportset,
+ CH_WIDTH_160MHZ,
+ 1);
+
+ simctx->curr_reportset = NULL;
+
+ simctx->is_enabled = false;
+ simctx->is_active = false;
+
+ simctx->ssim_starting_tsf64 = 0;
+ simctx->ssim_count = 0;
+ simctx->ssim_period_ms = 0;
+
+ return 0;
+}
+
+static void depopulate_simdata(ath_spectralsim_context *simctx)
+{
+ if (!simctx)
+ return;
+
+ SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw20_headreportset);
+ SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw40_headreportset);
+ SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw80_headreportset);
+ SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw160_headreportset);
+ SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(simctx->bw80_80_headreportset);
+}
+
+static
+OS_TIMER_FUNC(spectral_sim_phyerrdelivery_handler)
+{
+ struct target_if_spectral *spectral = NULL;
+ ath_spectralsim_context *simctx = NULL;
+ ath_spectralsim_reportset *curr_reportset = NULL;
+ ath_spectralsim_report *curr_report = NULL;
+ struct target_if_spectral_acs_stats acs_stats;
+ u_int64_t curr_tsf64 = 0;
+ struct target_if_spectral_ops *p_sops;
+
+ OS_GET_TIMER_ARG(spectral, struct target_if_spectral *);
+ qdf_assert_always(spectral);
+
+ p_sops = GET_TIF_SPECTRAL_OPS(spectral);
+ qdf_assert_always(spectral);
+
+ simctx = (ath_spectralsim_context *)spectral->simctx;
+ qdf_assert_always(simctx);
+
+ if (!simctx->is_active)
+ return;
+
+ curr_reportset = simctx->curr_reportset;
+ qdf_assert_always(curr_reportset);
+
+ curr_report = curr_reportset->curr_report;
+ qdf_assert_always(curr_report);
+
+ qdf_assert_always(curr_reportset->headreport);
+
+ /* We use a simulation TSF since in offload architectures we can't
+ * expect to
+ * get an accurate current TSF from HW.
+ * In case of TSF wrap over, we'll use it as-is for now since the
+ * simulation
+ * is intended only for format verification.
+ */
+ curr_tsf64 = simctx->ssim_starting_tsf64 +
+ ((simctx->ssim_period_ms * simctx->ssim_count) * 1000);
+
+ p_sops->spectral_process_phyerr(spectral,
+ curr_report->data,
+ curr_report->datasize,
+ &curr_report->rfqual_info,
+ &curr_report->chan_info,
+ curr_tsf64,
+ &acs_stats);
+
+ simctx->ssim_count++;
+
+ if (curr_report->next)
+ curr_reportset->curr_report = curr_report->next;
+ else
+ curr_reportset->curr_report = curr_reportset->headreport;
+
+ if (curr_reportset->config.ss_count != 0 &&
+ simctx->ssim_count == curr_reportset->config.ss_count) {
+ tif_spectral_sim_stop_spectral_scan(spectral);
+ } else {
+ qdf_timer_start(&simctx->ssim_pherrdelivery_timer,
+ simctx->ssim_period_ms);
+ }
+}
+
+/* Module services */
+
+int target_if_spectral_sim_attach(struct target_if_spectral *spectral)
+{
+ ath_spectralsim_context *simctx = NULL;
+
+ qdf_assert_always(spectral);
+
+ simctx = (ath_spectralsim_context *)
+ qdf_mem_malloc(sizeof(ath_spectralsim_context));
+
+ if (!simctx) {
+ qdf_print("Spectral simulation: Could not allocate memory for "
+ "context\n");
+ return -EPERM;
+ }
+
+ qdf_mem_zero(simctx, sizeof(*simctx));
+
+ spectral->simctx = simctx;
+
+ if (spectral->spectral_gen == SPECTRAL_GEN2)
+ simctx->populate_report_static = populate_report_static_gen2;
+ else if (spectral->spectral_gen == SPECTRAL_GEN3)
+ simctx->populate_report_static = populate_report_static_gen3;
+
+ if (populate_simdata(simctx) != 0) {
+ qdf_mem_free(simctx);
+ spectral->simctx = NULL;
+ qdf_print("Spectral simulation attach failed\n");
+ return -EPERM;
+ }
+
+ qdf_timer_init(NULL,
+ &simctx->ssim_pherrdelivery_timer,
+ spectral_sim_phyerrdelivery_handler,
+ (void *)(spectral),
+ QDF_TIMER_TYPE_WAKE_APPS);
+
+ qdf_print("Spectral simulation attached\n");
+
+ return 0;
+}
+
+void target_if_spectral_sim_detach(struct target_if_spectral *spectral)
+{
+ ath_spectralsim_context *simctx = NULL;
+
+ qdf_assert_always(spectral);
+
+ simctx = (ath_spectralsim_context *)spectral->simctx;
+ qdf_assert_always(simctx);
+
+ qdf_timer_free(&simctx->ssim_pherrdelivery_timer);
+
+ depopulate_simdata(simctx);
+ qdf_mem_free(simctx);
+ spectral->simctx = NULL;
+
+ qdf_print("Spectral simulation detached\n");
+}
+
+u_int32_t tif_spectral_sim_is_spectral_active(void *arg)
+{
+ struct target_if_spectral *spectral = NULL;
+ ath_spectralsim_context *simctx = NULL;
+
+ spectral = (struct target_if_spectral *)arg;
+ qdf_assert_always(spectral);
+
+ simctx = (ath_spectralsim_context *)spectral->simctx;
+ qdf_assert_always(simctx);
+
+ return simctx->is_active;
+}
+EXPORT_SYMBOL(tif_spectral_sim_is_spectral_active);
+
+u_int32_t tif_spectral_sim_is_spectral_enabled(void *arg)
+{
+ struct target_if_spectral *spectral = NULL;
+ ath_spectralsim_context *simctx = NULL;
+
+ spectral = (struct target_if_spectral *)arg;
+ qdf_assert_always(spectral);
+
+ simctx = (ath_spectralsim_context *)spectral->simctx;
+ qdf_assert_always(simctx);
+
+ return simctx->is_enabled;
+}
+EXPORT_SYMBOL(tif_spectral_sim_is_spectral_enabled);
+
+u_int32_t tif_spectral_sim_start_spectral_scan(void *arg)
+{
+ struct target_if_spectral *spectral = NULL;
+ ath_spectralsim_context *simctx = NULL;
+
+ spectral = (struct target_if_spectral *)arg;
+ qdf_assert_always(spectral);
+
+ simctx = (ath_spectralsim_context *)spectral->simctx;
+ qdf_assert_always(simctx);
+
+ if (!simctx->curr_reportset) {
+ qdf_print("Spectral simulation: No current report set "
+ "configured - unable to start simulated Spectral "
+ "scan\n");
+ return 0;
+ }
+
+ if (!simctx->curr_reportset->curr_report) {
+ qdf_print("Spectral simulation: No report data instances "
+ "populated - unable to start simulated Spectral "
+ "scan\n");
+ return 0;
+ }
+
+ if (!simctx->is_enabled)
+ simctx->is_enabled = true;
+
+ simctx->is_active = true;
+
+ /* Hardcoding current time as zero since it is simulation */
+ simctx->ssim_starting_tsf64 = 0;
+ simctx->ssim_count = 0;
+
+ /* TODO: Support high resolution timer in microseconds if required, so
+ * that
+ * we can support default periods such as ~200 us. For now, we use 1
+ * millisecond since the current use case for the simulation is to
+ * validate
+ * formats rather than have a time dependent classification.
+ */
+ simctx->ssim_period_ms = 1;
+
+ qdf_timer_start(&simctx->ssim_pherrdelivery_timer,
+ simctx->ssim_period_ms);
+
+ return 1;
+}
+EXPORT_SYMBOL(tif_spectral_sim_start_spectral_scan);
+
+u_int32_t tif_spectral_sim_stop_spectral_scan(void *arg)
+{
+ struct target_if_spectral *spectral = NULL;
+ ath_spectralsim_context *simctx = NULL;
+
+ spectral = (struct target_if_spectral *)arg;
+ qdf_assert_always(spectral);
+
+ simctx = (ath_spectralsim_context *)spectral->simctx;
+ qdf_assert_always(simctx);
+
+ qdf_timer_stop(&simctx->ssim_pherrdelivery_timer);
+
+ simctx->is_active = false;
+ simctx->is_enabled = false;
+
+ simctx->ssim_starting_tsf64 = 0;
+ simctx->ssim_count = 0;
+ simctx->ssim_period_ms = 0;
+
+ return 1;
+}
+EXPORT_SYMBOL(tif_spectral_sim_stop_spectral_scan);
+
+u_int32_t tif_spectral_sim_configure_params(
+ void *arg,
+ struct spectral_config *params)
+{
+ struct target_if_spectral *spectral = NULL;
+ ath_spectralsim_context *simctx = NULL;
+ enum wlan_phymode phymode;
+ u_int8_t bw;
+ ath_spectralsim_reportset *des_headreportset = NULL;
+ ath_spectralsim_reportset *temp_reportset = NULL;
+ bool is_invalid_width = false;
+ struct wlan_objmgr_vdev *vdev = NULL;
+
+ qdf_assert_always(params);
+
+#ifdef SPECTRAL_SIM_DUMP_PARAM_DATA
+ {
+ int i = 0;
+
+ qdf_print("\n");
+
+ qdf_print("Spectral simulation: Param data dump:\n"
+ "ss_fft_period=%hu\n"
+ "ss_period=%hu\n"
+ "ss_count=%hu\n"
+ "ss_short_report=%hu\n"
+ "radar_bin_thresh_sel=%hhu\n"
+ "ss_spectral_pri=%hu\n"
+ "ss_fft_size=%hu\n"
+ "ss_gc_ena=%hu\n"
+ "ss_restart_ena=%hu\n"
+ "ss_noise_floor_ref=%hu\n"
+ "ss_init_delay=%hu\n"
+ "ss_nb_tone_thr=%hu\n"
+ "ss_str_bin_thr=%hu\n"
+ "ss_wb_rpt_mode=%hu\n"
+ "ss_rssi_rpt_mode=%hu\n"
+ "ss_rssi_thr=%hu\n"
+ "ss_pwr_format=%hu\n"
+ "ss_rpt_mode=%hu\n"
+ "ss_bin_scale=%hu\n"
+ "ss_dBm_adj=%hu\n"
+ "ss_chn_mask=%hu\n"
+ "ss_nf_temp_data=%d\n",
+ params->ss_fft_period,
+ params->ss_period,
+ params->ss_count,
+ params->ss_short_report,
+ params->radar_bin_thresh_sel,
+ params->ss_spectral_pri,
+ params->ss_fft_size,
+ params->ss_gc_ena,
+ params->ss_restart_ena,
+ params->ss_noise_floor_ref,
+ params->ss_init_delay,
+ params->ss_nb_tone_thr,
+ params->ss_str_bin_thr,
+ params->ss_wb_rpt_mode,
+ params->ss_rssi_rpt_mode,
+ params->ss_rssi_thr,
+ params->ss_pwr_format,
+ params->ss_rpt_mode,
+ params->ss_bin_scale,
+ params->ss_dBm_adj,
+ params->ss_chn_mask,
+ params->ss_nf_temp_data);
+
+ for (i = 0; i < AH_MAX_CHAINS * 2; i++)
+ qdf_print("ss_nf_cal[%d]=%hhd\n", i, params->ss_nf_cal[i]);
+
+ for (i = 0; i < AH_MAX_CHAINS * 2; i++)
+ qdf_print("ss_nf_pwr[%d]=%hhd\n", i, params->ss_nf_pwr[i]);
+
+ qdf_print("\n");
+ }
+#endif /* SPECTRAL_SIM_DUMP_PARAM_DATA */
+
+ spectral = (struct target_if_spectral *)arg;
+ qdf_assert_always(spectral);
+
+ simctx = (ath_spectralsim_context *)spectral->simctx;
+ qdf_assert_always(simctx);
+
+ vdev = target_if_spectral_get_vdev(spectral);
+ if (!vdev) {
+ qdf_print("Spectral simulation: No VAPs found - not proceeding"
+ " with param config.\n");
+ return 0;
+ }
+
+ bw = wlan_vdev_get_ch_width(vdev);
+
+ switch (bw) {
+ case CH_WIDTH_20MHZ:
+ des_headreportset = simctx->bw20_headreportset;
+ break;
+ case CH_WIDTH_40MHZ:
+ des_headreportset = simctx->bw40_headreportset;
+ break;
+ case CH_WIDTH_80MHZ:
+ des_headreportset = simctx->bw80_headreportset;
+ break;
+ case CH_WIDTH_160MHZ:
+ phymode = wlan_vdev_get_phymode(vdev);
+ if (phymode == WLAN_PHYMODE_11AC_VHT160) {
+ des_headreportset = simctx->bw160_headreportset;
+ } else if (phymode == WLAN_PHYMODE_11AC_VHT80_80) {
+ des_headreportset = simctx->bw80_80_headreportset;
+ } else {
+ qdf_print("Spectral simulation: Unexpected PHY mode %u"
+ " found for width 160 MHz...asserting.\n",
+ phymode);
+ qdf_assert_always(0);
+ }
+ break;
+
+ case IEEE80211_CWM_WIDTHINVALID:
+ qdf_print("Spectral simulation: Invalid width configured - not"
+ " proceeding with param config.\n");
+ is_invalid_width = true;
+ default:
+ qdf_print("Spectral simulation: Unknown width %u...asserting\n"
+ , bw);
+ qdf_assert_always(0);
+ break;
+ }
+
+ wlan_objmgr_vdev_release_ref(vdev, WLAN_SPECTRAL_ID);
+
+ if (is_invalid_width)
+ return 0;
+
+ if (!des_headreportset) {
+ qdf_print("Spectral simulation: No simulation data present for"
+ " configured bandwidth/PHY mode - unable to proceed "
+ " with param config.\n");
+ return 0;
+ }
+
+ simctx->curr_reportset = NULL;
+ temp_reportset = des_headreportset;
+
+ while (temp_reportset) {
+ if (qdf_mem_cmp(&temp_reportset->config,
+ params, sizeof(struct spectral_config)) == 0) {
+ /* Found a matching config. We are done. */
+ simctx->curr_reportset = temp_reportset;
+ break;
+ }
+
+ temp_reportset = temp_reportset->next;
+ }
+
+ if (!simctx->curr_reportset) {
+ qdf_print("Spectral simulation: No simulation data present for"
+ " desired Spectral configuration - unable to proceed"
+ " with param config.\n");
+ return 0;
+ }
+
+ if (!simctx->curr_reportset->curr_report) {
+ qdf_print("Spectral simulation: No report data instances "
+ "populated for desired Spectral configuration - "
+ "unable to proceed with param config\n");
+ return 0;
+ }
+
+ return 1;
+}
+EXPORT_SYMBOL(tif_spectral_sim_configure_params);
+
+u_int32_t tif_spectral_sim_get_params(
+ void *arg,
+ struct spectral_config *params)
+{
+ struct target_if_spectral *spectral = NULL;
+ ath_spectralsim_context *simctx = NULL;
+
+ qdf_assert_always(params);
+
+ spectral = (struct target_if_spectral *)arg;
+ qdf_assert_always(spectral);
+
+ simctx = (ath_spectralsim_context *)spectral->simctx;
+ qdf_assert_always(simctx);
+
+ if (!simctx->curr_reportset) {
+ qdf_print("Spectral simulation: No configured reportset found.\n");
+ return 0;
+ }
+
+ qdf_mem_copy(params, &simctx->curr_reportset->config, sizeof(*params));
+
+ return 1;
+}
+EXPORT_SYMBOL(tif_spectral_sim_get_params);
+
+#endif /* QCA_SUPPORT_SPECTRAL_SIMULATION */
diff --git a/target_if/spectral/target_if_spectral_sim.h b/target_if/spectral/target_if_spectral_sim.h
new file mode 100644
index 0000000..d0e9411
--- /dev/null
+++ b/target_if/spectral/target_if_spectral_sim.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2015,2017 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SPECTRAL_SIM_H_
+#define _SPECTRAL_SIM_H_
+
+#if QCA_SUPPORT_SPECTRAL_SIMULATION
+#include "target_if_spectral.h"
+
+/**
+ * @brief Initialize Spectral Simulation functionality
+ * @details
+ * Setup data structures to be used for serving out data corresponding to
+ * various bandwidths and configurations.
+ *
+ * @param spectral - ath_spectral structure
+ * @return Integer status value. 0:Success, -1:Failure
+ */
+int target_if_spectral_sim_attach(struct target_if_spectral *spectral);
+
+/**
+ * @brief De-initialize Spectral Simulation functionality
+ * @details
+ * Free up data structures used for serving out data corresponding to various
+ * bandwidths and configurations.
+ *
+ * @param spectral - ath_spectral structure
+ */
+void target_if_spectral_sim_detach(struct target_if_spectral *spectral);
+
+/**
+ * @brief Check if Spectral (simulated) is active
+ *
+ * @param arg - pointer to ath_spectral structure
+ * @return Integer status value. 0: Not active, 1: Active
+ */
+u_int32_t tif_spectral_sim_is_spectral_active(void *arg);
+
+/**
+ * @brief Check if Spectral (simulated) is enabled
+ *
+ * @param arg - pointer to ath_spectral structure
+ * @return Integer status value. 0: Not enabled, 1: Enabled
+ */
+u_int32_t tif_spectral_sim_is_spectral_enabled(void *arg);
+
+/**
+ * @brief Start Spectral simulation
+ *
+ * @param arg - pointer to ath_spectral structure
+ * @return Integer status value. 0: Failure, 1: Success
+ */
+u_int32_t tif_spectral_sim_start_spectral_scan(void *arg);
+
+/**
+ * @brief Stop Spectral simulation
+ *
+ * @param arg - pointer to ath_spectral structure
+ * @return Integer status value. 0: Failure, 1: Success
+ */
+u_int32_t tif_spectral_sim_stop_spectral_scan(void *arg);
+
+/**
+ * @brief Configure Spectral parameters into simulation
+ * @details
+ * Internally, this function actually searches if a record set with the desired
+ * configuration has been loaded. If so, it points to the record set for
+ * later usage when the simulation is started. If not, it returns an error.
+ *
+ * @param arg - pointer to ath_spectral structure
+ * @param params - pointer to struct spectral_config structure bearing Spectral
+ * configuration
+ * @return Integer status value. 0: Failure, 1: Success
+ */
+u_int32_t tif_spectral_sim_configure_params(
+ void *arg,
+ struct spectral_config *params);
+
+/**
+ * @brief Get Spectral parameters configured into simulation
+ *
+ * @param arg - pointer to ath_spectral structure
+ * @param params - pointer to struct spectral_config structure which should be
+ * populated with Spectral configuration
+ * @return Integer status value. 0: Failure, 1: Success
+ */
+u_int32_t tif_spectral_sim_get_params(
+ void *arg,
+ struct spectral_config *params);
+
+#endif /* QCA_SUPPORT_SPECTRAL_SIMULATION */
+#endif /* _SPECTRAL_SIM_H_ */
diff --git a/target_if/spectral/target_if_spectral_sim_int.h b/target_if/spectral/target_if_spectral_sim_int.h
new file mode 100644
index 0000000..c0b5332
--- /dev/null
+++ b/target_if/spectral/target_if_spectral_sim_int.h
@@ -0,0 +1,961 @@
+/*
+ * Copyright (c) 2015,2017 The Linux Foundation. All rights reserved.
+ *
+ *
+ * Permission to use, copy, modify, and/or distribute this software for
+ * any purpose with or without fee is hereby granted, provided that the
+ * above copyright notice and this permission notice appear in all
+ * copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
+ * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
+ * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _SPECTRAL_SIM_INTERNAL_H_
+#define _SPECTRAL_SIM_INTERNAL_H_
+
+#if QCA_SUPPORT_SPECTRAL_SIMULATION
+#include "target_if_spectral.h"
+
+/* #define SPECTRAL_SIM_DUMP_PARAM_DATA 1 */
+/* Spectral report data instance. Usable in a linked list.
+ * - In the case of Direct Attach chipsets, one instance should correspond to
+ * one PHY Data Error frame received from the HW.
+ * XXX Direct Attach support to be implemented if needed. Any modifications
+ * required here can be made at the time of implementation.
+ * - In the case of 802.11ac offload chipsets, one instance should correspond to
+ * one report received from HW, inclusive of all TLVs.
+ */
+typedef struct _ath_spectralsim_report {
+ /* 11ac onwards only */
+ struct target_if_spectral_rfqual_info rfqual_info;
+ /* 11ac onwards only */
+ struct target_if_spectral_chan_info chan_info;
+ u_int32_t datasize;
+ u_int8_t *data;
+ struct _ath_spectralsim_report *next;
+} ath_spectralsim_report;
+
+/* Set of Spectral report data instances corresponding to one particular
+ * configuration. Usable in a linked list.
+ */
+typedef struct _ath_spectralsim_reportset {
+ struct spectral_config config;
+ ath_spectralsim_report *headreport;
+ ath_spectralsim_report *curr_report;
+ struct _ath_spectralsim_reportset *next;
+} ath_spectralsim_reportset;
+
+/* Main structure for Spectral simulation. All data and controls get linked
+ * here.
+ *
+ * For each width (20/40/80/160/80+80), we will have a linked list of
+ * ath_spectralsim_reportset nodes. Each ath_spectralsim_reportset will have a
+ * linked list of ath_spectralsim_report nodes. When the user requests for a
+ * given PHY mode and Spectral configuration, we find the appropriate
+ * ath_spectralsim_reportset, and then serve ath_spectralsim_report instances
+ * from the linked list. If required report count is higher than size of linked
+ * list (or infinite), we repeatedly cycle through the linked list. There can
+ * be more elaborate data structures devised taking care of a large number of
+ * possibilities, but we stick to a simple scheme given limited simulation
+ * needs.
+ */
+typedef struct _ath_spectralsim_context {
+ ath_spectralsim_reportset *bw20_headreportset;
+ ath_spectralsim_reportset *bw40_headreportset;
+ ath_spectralsim_reportset *bw80_headreportset;
+ ath_spectralsim_reportset *bw160_headreportset;
+ ath_spectralsim_reportset *bw80_80_headreportset;
+
+ ath_spectralsim_reportset *curr_reportset;
+ bool is_enabled;
+ bool is_active;
+
+ qdf_timer_t ssim_pherrdelivery_timer;
+ u_int64_t ssim_starting_tsf64;
+ u_int32_t ssim_period_ms; /* TODO: Support in microseconds */
+ u_int32_t ssim_count;
+ int (*populate_report_static)(ath_spectralsim_report *report,
+ enum phy_ch_width width,
+ bool is_80_80);
+} ath_spectralsim_context;
+
+/* Helper Macros */
+
+/* Allocate and populate reportset for a single configuration */
+#define SPECTRAL_SIM_REPORTSET_ALLOCPOPL_SINGLE(simctx, reportset, width, \
+ is_80_80) \
+ { \
+ (reportset) = (ath_spectralsim_reportset *) \
+ qdf_mem_malloc(sizeof(ath_spectralsim_reportset)); \
+ \
+ if ((reportset) == NULL) { \
+ qdf_print("Spectral simulation: Could not allocate memory " \
+ "for report set\n"); \
+ depopulate_simdata((simctx)); \
+ return -EPERM; \
+ } \
+ \
+ qdf_mem_zero((reportset), sizeof(ath_spectralsim_reportset)); \
+ \
+ if (populate_reportset_static( \
+ (simctx), (reportset), (width), (is_80_80)) != 0) { \
+ depopulate_simdata((simctx)); \
+ return -EPERM; \
+ } \
+ \
+ (reportset)->next = NULL; \
+ }
+
+/* Depopulate and free list of report sets */
+#define SPECTRAL_SIM_REPORTSET_DEPOPLFREE_LIST(reportset) \
+ { \
+ ath_spectralsim_reportset *curr_reportset = NULL; \
+ ath_spectralsim_reportset *next_reportset = NULL; \
+ \
+ curr_reportset = (reportset); \
+ \
+ while (curr_reportset) { \
+ next_reportset = curr_reportset->next; \
+ depopulate_reportset(curr_reportset); \
+ qdf_mem_free(curr_reportset); \
+ curr_reportset = next_reportset; \
+ } \
+ \
+ (reportset) = NULL; \
+ }
+
+/* Values for static population */
+
+/* 20 MHz */
+
+static uint8_t reportdata_20_gen2[] = {
+#ifdef BIG_ENDIAN_HOST
+ 0xbb, /* Signature */
+ 0xfb, /* Tag */
+ 0x00, /* Size */
+ 0x54,
+ 0x2e, 0x60, 0x0f, 0xe8, /* FFT Summary A */
+ 0x00, 0x00, 0x04, 0x00, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x00, /* Segment ID */
+#else
+ 0x54, /* Length */
+ 0x00,
+ 0xfb, /* Tag */
+ 0xbb, /* Signature */
+ 0xe8, 0x0f, 0x60, 0x2e, /* FFT Summary A */
+ 0x00, 0x04, 0x00, 0x00, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x00, /* Segment ID */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 1, 2, 0, 1, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1,
+ 1, 1, 0, 2, 1, 2, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0,
+};
+
+static uint8_t reportdata_20_gen3[] = {
+#ifdef BIG_ENDIAN_HOST
+ 0x12, 0x34, 0x56, 0x78, /* fft_timestamp */
+ 0xfa, /* fft_hdr_sig */
+ 0x03, /* fft_hdr_tag */
+ 0x00, /* fft_hdr_length */
+ 0x14,
+ 0x0f, 0xf6, 0x00, 0xe0,
+ 0x00, 0x00, 0x2f, 0xba,
+ 0x20, 0xb4, 0x2c, 0x01,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#else
+ 0x78, 0x56, 0x34, 0x12, /* fft_timestamp */
+ 0x14, /* fft_hdr_length */
+ 0x00,
+ 0x03, /* fft_hdr_tag */
+ 0xfa, /* fft_hdr_sig */
+ 0xe0, 0x00, 0xf6, 0x0f,
+ 0xba, 0x2f, 0x00, 0x00,
+ 0x01, 0x2c, 0xb4, 0x20,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 0, 1, 2, 0, 1, 1, 1, 0,
+ 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1,
+ 1, 1, 0, 2, 1, 2, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0,
+};
+
+static struct target_if_spectral_rfqual_info rfqual_info_20 = {
+ .rssi_comb = 1,
+
+ .pc_rssi_info[0].rssi_pri20 = 1,
+ .pc_rssi_info[0].rssi_sec20 = 128,
+ .pc_rssi_info[0].rssi_sec40 = 128,
+ .pc_rssi_info[0].rssi_sec80 = 128,
+
+ .pc_rssi_info[1].rssi_pri20 = 128,
+ .pc_rssi_info[1].rssi_sec20 = 128,
+ .pc_rssi_info[1].rssi_sec40 = 128,
+ .pc_rssi_info[1].rssi_sec80 = 128,
+
+ .pc_rssi_info[2].rssi_pri20 = 128,
+ .pc_rssi_info[2].rssi_sec20 = 128,
+ .pc_rssi_info[2].rssi_sec40 = 128,
+ .pc_rssi_info[2].rssi_sec80 = 128,
+
+ .pc_rssi_info[3].rssi_pri20 = 128,
+ .pc_rssi_info[3].rssi_sec20 = 128,
+ .pc_rssi_info[3].rssi_sec40 = 128,
+ .pc_rssi_info[3].rssi_sec80 = 128,
+
+ .noise_floor[0] = -90,
+ .noise_floor[1] = -90,
+ .noise_floor[2] = -90,
+ .noise_floor[3] = -90,
+ };
+
+static struct target_if_spectral_chan_info chan_info_20 = {
+ .center_freq1 = 5180,
+ .center_freq2 = 0,
+ .chan_width = 20,
+ };
+
+static struct spectral_config config_20_1 = {
+ .ss_fft_period = 1,
+ .ss_period = 35,
+ .ss_count = 0,
+ .ss_short_report = 1,
+ .radar_bin_thresh_sel = 0,
+ .ss_spectral_pri = 1,
+ .ss_fft_size = 7,
+ .ss_gc_ena = 1,
+ .ss_restart_ena = 0,
+ .ss_noise_floor_ref = 65440,
+ .ss_init_delay = 80,
+ .ss_nb_tone_thr = 12,
+ .ss_str_bin_thr = 8,
+ .ss_wb_rpt_mode = 0,
+ .ss_rssi_rpt_mode = 0,
+ .ss_rssi_thr = 240,
+ .ss_pwr_format = 0,
+ .ss_rpt_mode = 2,
+ .ss_bin_scale = 1,
+ .ss_dBm_adj = 1,
+ .ss_chn_mask = 1,
+ .ss_nf_cal[0] = 0,
+ .ss_nf_cal[1] = 0,
+ .ss_nf_cal[2] = 0,
+ .ss_nf_cal[3] = 0,
+ .ss_nf_cal[4] = 0,
+ .ss_nf_cal[5] = 0,
+ .ss_nf_pwr[0] = 0,
+ .ss_nf_pwr[1] = 0,
+ .ss_nf_pwr[2] = 0,
+ .ss_nf_pwr[3] = 0,
+ .ss_nf_pwr[4] = 0,
+ .ss_nf_pwr[5] = 0,
+ .ss_nf_temp_data = 0,
+ };
+
+/* 40 MHz */
+
+static uint8_t reportdata_40_gen2[] = {
+#ifdef BIG_ENDIAN_HOST
+ 0xbb, /* Signature */
+ 0xfb, /* Tag */
+ 0x00, /* Size */
+ 0x94,
+ 0x2e, 0x61, 0x0f, 0x80, /* FFT Summary A */
+ 0x00, 0x00, 0x06, 0x00, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x00, /* Segment ID */
+#else
+ 0x94, /* Length */
+ 0x00,
+ 0xfb, /* Tag */
+ 0xbb, /* Signature */
+ 0x80, 0x0f, 0x61, 0x2e, /* FFT Summary A */
+ 0x00, 0x06, 0x00, 0x00, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x00, /* Segment ID */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0,
+};
+
+static uint8_t reportdata_40_gen3[] = {
+#ifdef BIG_ENDIAN_HOST
+ 0x12, 0x34, 0x56, 0x78, /* fft_timestamp */
+ 0xfa, /* fft_hdr_sig */
+ 0x03, /* fft_hdr_tag */
+ 0x00, /* fft_hdr_length */
+ 0x24,
+ 0x0f, 0xf6, 0x00, 0xe0,
+ 0x00, 0x00, 0x2f, 0xba,
+ 0x20, 0xb4, 0x2c, 0x01,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#else
+ 0x78, 0x56, 0x34, 0x12, /* fft_timestamp */
+ 0x24, /* fft_hdr_length */
+ 0x00,
+ 0x03, /* fft_hdr_tag */
+ 0xfa, /* fft_hdr_sig */
+ 0xe0, 0x00, 0xf6, 0x0f,
+ 0xba, 0x2f, 0x00, 0x00,
+ 0x01, 0x2c, 0xb4, 0x20,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1,
+ 0, 0, 0, 1, 0, 0, 0, 0, 2, 1, 0, 2, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0,
+ 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 1, 0, 0, 0, 0,
+};
+
+static struct target_if_spectral_rfqual_info rfqual_info_40 = {
+ .rssi_comb = 1,
+
+ .pc_rssi_info[0].rssi_pri20 = 1,
+ .pc_rssi_info[0].rssi_sec20 = 2,
+ .pc_rssi_info[0].rssi_sec40 = 128,
+ .pc_rssi_info[0].rssi_sec80 = 128,
+
+ .pc_rssi_info[1].rssi_pri20 = 128,
+ .pc_rssi_info[1].rssi_sec20 = 128,
+ .pc_rssi_info[1].rssi_sec40 = 128,
+ .pc_rssi_info[1].rssi_sec80 = 128,
+
+ .pc_rssi_info[2].rssi_pri20 = 128,
+ .pc_rssi_info[2].rssi_sec20 = 128,
+ .pc_rssi_info[2].rssi_sec40 = 128,
+ .pc_rssi_info[2].rssi_sec80 = 128,
+
+ .pc_rssi_info[3].rssi_pri20 = 128,
+ .pc_rssi_info[3].rssi_sec20 = 128,
+ .pc_rssi_info[3].rssi_sec40 = 128,
+ .pc_rssi_info[3].rssi_sec80 = 128,
+
+ .noise_floor[0] = -90,
+ .noise_floor[1] = -90,
+ .noise_floor[2] = -90,
+ .noise_floor[3] = -90,
+ };
+
+static struct target_if_spectral_chan_info chan_info_40 = {
+ .center_freq1 = 5180,
+ .center_freq2 = 0,
+ .chan_width = 40,
+ };
+
+static struct spectral_config config_40_1 = {
+ .ss_fft_period = 1,
+ .ss_period = 35,
+ .ss_count = 0,
+ .ss_short_report = 1,
+ .radar_bin_thresh_sel = 0,
+ .ss_spectral_pri = 1,
+ .ss_fft_size = 8,
+ .ss_gc_ena = 1,
+ .ss_restart_ena = 0,
+ .ss_noise_floor_ref = 65440,
+ .ss_init_delay = 80,
+ .ss_nb_tone_thr = 12,
+ .ss_str_bin_thr = 8,
+ .ss_wb_rpt_mode = 0,
+ .ss_rssi_rpt_mode = 0,
+ .ss_rssi_thr = 240,
+ .ss_pwr_format = 0,
+ .ss_rpt_mode = 2,
+ .ss_bin_scale = 1,
+ .ss_dBm_adj = 1,
+ .ss_chn_mask = 1,
+ .ss_nf_cal[0] = 0,
+ .ss_nf_cal[1] = 0,
+ .ss_nf_cal[2] = 0,
+ .ss_nf_cal[3] = 0,
+ .ss_nf_cal[4] = 0,
+ .ss_nf_cal[5] = 0,
+ .ss_nf_pwr[0] = 0,
+ .ss_nf_pwr[1] = 0,
+ .ss_nf_pwr[2] = 0,
+ .ss_nf_pwr[3] = 0,
+ .ss_nf_pwr[4] = 0,
+ .ss_nf_pwr[5] = 0,
+ .ss_nf_temp_data = 0,
+ };
+
+/* 80 MHz */
+
+static uint8_t reportdata_80_gen2[] = {
+#ifdef BIG_ENDIAN_HOST
+ 0xbb, /* Signature */
+ 0xfb, /* Tag */
+ 0x01, /* Size */
+ 0x14,
+ 0x19, 0xeb, 0x80, 0x40, /* FFT Summary A */
+ 0x00, 0x00, 0x10, 0x00, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x00, /* Segment ID */
+#else
+ 0x14, /* Length */
+ 0x01,
+ 0xfb, /* Tag */
+ 0xbb, /* Signature */
+ 0x40, 0x80, 0xeb, 0x19, /* FFT Summary A */
+ 0x00, 0x10, 0x00, 0x00, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x00, /* Segment ID */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static uint8_t reportdata_80_gen3[] = {
+#ifdef BIG_ENDIAN_HOST
+ 0x12, 0x34, 0x56, 0x78, /* fft_timestamp */
+ 0xfa, /* fft_hdr_sig */
+ 0x03, /* fft_hdr_tag */
+ 0x00, /* fft_hdr_length */
+ 0x44,
+ 0x0f, 0xf6, 0x00, 0xe0,
+ 0x00, 0x00, 0x2f, 0xba,
+ 0x20, 0xb4, 0x2c, 0x01,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#else
+ 0x78, 0x56, 0x34, 0x12, /* fft_timestamp */
+ 0x44, /* fft_hdr_length */
+ 0x00,
+ 0x03, /* fft_hdr_tag */
+ 0xfa, /* fft_hdr_sig */
+ 0xe0, 0x00, 0xf6, 0x0f,
+ 0xba, 0x2f, 0x00, 0x00,
+ 0x01, 0x2c, 0xb4, 0x20,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static struct target_if_spectral_rfqual_info rfqual_info_80 = {
+ .rssi_comb = 16,
+
+ .pc_rssi_info[0].rssi_pri20 = 16,
+ .pc_rssi_info[0].rssi_sec20 = 17,
+ .pc_rssi_info[0].rssi_sec40 = 0,
+ .pc_rssi_info[0].rssi_sec80 = 128,
+
+ .pc_rssi_info[1].rssi_pri20 = 128,
+ .pc_rssi_info[1].rssi_sec20 = 128,
+ .pc_rssi_info[1].rssi_sec40 = 128,
+ .pc_rssi_info[1].rssi_sec80 = 128,
+
+ .pc_rssi_info[2].rssi_pri20 = 128,
+ .pc_rssi_info[2].rssi_sec20 = 128,
+ .pc_rssi_info[2].rssi_sec40 = 128,
+ .pc_rssi_info[2].rssi_sec80 = 128,
+
+ .pc_rssi_info[3].rssi_pri20 = 128,
+ .pc_rssi_info[3].rssi_sec20 = 128,
+ .pc_rssi_info[3].rssi_sec40 = 128,
+ .pc_rssi_info[3].rssi_sec80 = 128,
+
+ .noise_floor[0] = -90,
+ .noise_floor[1] = -90,
+ .noise_floor[2] = -90,
+ .noise_floor[3] = -90,
+ };
+
+static struct target_if_spectral_chan_info chan_info_80 = {
+ .center_freq1 = 5210,
+ .center_freq2 = 0,
+ .chan_width = 80,
+ };
+
+static struct spectral_config config_80_1 = {
+ .ss_fft_period = 1,
+ .ss_period = 35,
+ .ss_count = 0,
+ .ss_short_report = 1,
+ .radar_bin_thresh_sel = 0,
+ .ss_spectral_pri = 1,
+ .ss_fft_size = 9,
+ .ss_gc_ena = 1,
+ .ss_restart_ena = 0,
+ .ss_noise_floor_ref = 65440,
+ .ss_init_delay = 80,
+ .ss_nb_tone_thr = 12,
+ .ss_str_bin_thr = 8,
+ .ss_wb_rpt_mode = 0,
+ .ss_rssi_rpt_mode = 0,
+ .ss_rssi_thr = 240,
+ .ss_pwr_format = 0,
+ .ss_rpt_mode = 2,
+ .ss_bin_scale = 1,
+ .ss_dBm_adj = 1,
+ .ss_chn_mask = 1,
+ .ss_nf_cal[0] = 0,
+ .ss_nf_cal[1] = 0,
+ .ss_nf_cal[2] = 0,
+ .ss_nf_cal[3] = 0,
+ .ss_nf_cal[4] = 0,
+ .ss_nf_cal[5] = 0,
+ .ss_nf_pwr[0] = 0,
+ .ss_nf_pwr[1] = 0,
+ .ss_nf_pwr[2] = 0,
+ .ss_nf_pwr[3] = 0,
+ .ss_nf_pwr[4] = 0,
+ .ss_nf_pwr[5] = 0,
+ .ss_nf_temp_data = 0,
+ };
+
+/* 160 MHz */
+
+static uint8_t reportdata_160_gen2[] = {
+ /* Segment 1 */
+#ifdef BIG_ENDIAN_HOST
+ 0xbb, /* Signature */
+ 0xfb, /* Tag */
+ 0x01, /* Size */
+ 0x14,
+ 0x23, 0x66, 0x00, 0x40, /* FFT Summary A */
+ 0x5c, 0x5c, 0x78, 0x00, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x00, /* Segment ID */
+#else
+ 0x14, /* Length */
+ 0x01,
+ 0xfb, /* Tag */
+ 0xbb, /* Signature */
+ 0x40, 0x00, 0x66, 0x23, /* FFT Summary A */
+ 0x00, 0x78, 0x5c, 0x5c, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x00, /* Segment ID */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 2, 4, 60, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+
+ /* Segment 2 */
+#ifdef BIG_ENDIAN_HOST
+ 0xbb, /* Signature */
+ 0xfb, /* Tag */
+ 0x01, /* Size */
+ 0x14,
+ 0x23, 0x66, 0x00, 0x40, /* FFT Summary A */
+ 0x5c, 0x5c, 0x78, 0x00, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x01, /* Segment ID */
+#else
+ 0x14, /* Length */
+ 0x01,
+ 0xfb, /* Tag */
+ 0xbb, /* Signature */
+ 0x40, 0x00, 0x66, 0x23, /* FFT Summary A */
+ 0x00, 0x78, 0x5c, 0x5c, /* FFT Summary B */
+ 0x01, 0x00, 0x00, 0x00, /* Segment ID */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 2, 4, 60, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static uint8_t reportdata_160_gen3[] = {
+ /* Segment 1 */
+#ifdef BIG_ENDIAN_HOST
+ 0x12, 0x34, 0x56, 0x78, /* fft_timestamp */
+ 0xfa, /* fft_hdr_sig */
+ 0x03, /* fft_hdr_tag */
+ 0x00, /* fft_hdr_length */
+ 0x44,
+ 0x0f, 0xf6, 0x00, 0xe0,
+ 0x00, 0x00, 0x2f, 0xba,
+ 0x20, 0xb4, 0x2c, 0x01,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#else
+ 0x78, 0x56, 0x34, 0x12, /* fft_timestamp */
+ 0x44, /* fft_hdr_length */
+ 0x00,
+ 0x03, /* fft_hdr_tag */
+ 0xfa, /* fft_hdr_sig */
+ 0xe0, 0x00, 0xf6, 0x0f,
+ 0xba, 0x2f, 0x00, 0x00,
+ 0x01, 0x2c, 0xb4, 0x20,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 2, 4, 60, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* Segment 2 */
+#ifdef BIG_ENDIAN_HOST
+ 0x12, 0x34, 0x56, 0x78, /* fft_timestamp */
+ 0xfa, /* fft_hdr_sig */
+ 0x03, /* fft_hdr_tag */
+ 0x00, /* fft_hdr_length */
+ 0x44,
+ 0x0f, 0xf6, 0x00, 0xe1,
+ 0x00, 0x00, 0x2f, 0xba,
+ 0x20, 0xb4, 0x2c, 0x01,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#else
+ 0x78, 0x56, 0x34, 0x12, /* fft_timestamp */
+ 0x44, /* fft_hdr_length */
+ 0x00,
+ 0x03, /* fft_hdr_tag */
+ 0xfa, /* fft_hdr_sig */
+ 0xe1, 0x00, 0xf6, 0x0f,
+ 0xba, 0x2f, 0x00, 0x00,
+ 0x01, 0x2c, 0xb4, 0x20,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 2, 4, 60, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static struct target_if_spectral_rfqual_info rfqual_info_160 = {
+ .rssi_comb = 3,
+
+ .pc_rssi_info[0].rssi_pri20 = 3,
+ .pc_rssi_info[0].rssi_sec20 = 12,
+ .pc_rssi_info[0].rssi_sec40 = 41,
+ .pc_rssi_info[0].rssi_sec80 = 128,
+
+ .pc_rssi_info[1].rssi_pri20 = 128,
+ .pc_rssi_info[1].rssi_sec20 = 128,
+ .pc_rssi_info[1].rssi_sec40 = 128,
+ .pc_rssi_info[1].rssi_sec80 = 128,
+
+ .pc_rssi_info[2].rssi_pri20 = 128,
+ .pc_rssi_info[2].rssi_sec20 = 128,
+ .pc_rssi_info[2].rssi_sec40 = 128,
+ .pc_rssi_info[2].rssi_sec80 = 128,
+
+ .pc_rssi_info[3].rssi_pri20 = 128,
+ .pc_rssi_info[3].rssi_sec20 = 128,
+ .pc_rssi_info[3].rssi_sec40 = 128,
+ .pc_rssi_info[3].rssi_sec80 = 128,
+
+ .noise_floor[0] = -90,
+ .noise_floor[1] = -90,
+ .noise_floor[2] = -90,
+ .noise_floor[3] = -90,
+ };
+
+static struct target_if_spectral_chan_info chan_info_160 = {
+ .center_freq1 = 5250,
+ .center_freq2 = 0,
+ .chan_width = 160,
+ };
+
+static struct spectral_config config_160_1 = {
+ .ss_fft_period = 1,
+ .ss_period = 35,
+ .ss_count = 0,
+ .ss_short_report = 1,
+ .radar_bin_thresh_sel = 0,
+ .ss_spectral_pri = 1,
+ .ss_fft_size = 9,
+ .ss_gc_ena = 1,
+ .ss_restart_ena = 0,
+ .ss_noise_floor_ref = 65440,
+ .ss_init_delay = 80,
+ .ss_nb_tone_thr = 12,
+ .ss_str_bin_thr = 8,
+ .ss_wb_rpt_mode = 0,
+ .ss_rssi_rpt_mode = 0,
+ .ss_rssi_thr = 240,
+ .ss_pwr_format = 0,
+ .ss_rpt_mode = 2,
+ .ss_bin_scale = 1,
+ .ss_dBm_adj = 1,
+ .ss_chn_mask = 1,
+ .ss_nf_cal[0] = 0,
+ .ss_nf_cal[1] = 0,
+ .ss_nf_cal[2] = 0,
+ .ss_nf_cal[3] = 0,
+ .ss_nf_cal[4] = 0,
+ .ss_nf_cal[5] = 0,
+ .ss_nf_pwr[0] = 0,
+ .ss_nf_pwr[1] = 0,
+ .ss_nf_pwr[2] = 0,
+ .ss_nf_pwr[3] = 0,
+ .ss_nf_pwr[4] = 0,
+ .ss_nf_pwr[5] = 0,
+ .ss_nf_temp_data = 0,
+ };
+
+/* 80+80 MHz */
+
+static uint8_t reportdata_80_80_gen2[] = {
+ /* Segment 1 */
+#ifdef BIG_ENDIAN_HOST
+ 0xbb, /* Signature */
+ 0xfb, /* Tag */
+ 0x01, /* Size */
+ 0x14,
+ 0x23, 0x66, 0x00, 0x40, /* FFT Summary A */
+ 0x64, 0x64, 0x89, 0x00, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x00, /* Segment ID */
+#else
+ 0x14, /* Length */
+ 0x01,
+ 0xfb, /* Tag */
+ 0xbb, /* Signature */
+ 0x40, 0x00, 0x66, 0x23, /* FFT Summary A */
+ 0x00, 0x89, 0x64, 0x64, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x00, /* Segment ID */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 2, 6, 68, 5, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+
+ /* Segment 2 */
+#ifdef BIG_ENDIAN_HOST
+ 0xbb, /* Signature */
+ 0xfb, /* Tag */
+ 0x01, /* Size */
+ 0x14,
+ 0x23, 0x66, 0x00, 0x40, /* FFT Summary A */
+ 0x64, 0x64, 0x89, 0x00, /* FFT Summary B */
+ 0x00, 0x00, 0x00, 0x01, /* Segment ID */
+#else
+ 0x14, /* Length */
+ 0x01,
+ 0xfb, /* Tag */
+ 0xbb, /* Signature */
+ 0x40, 0x00, 0x66, 0x23, /* FFT Summary A */
+ 0x00, 0x89, 0x64, 0x64, /* FFT Summary B */
+ 0x01, 0x00, 0x00, 0x00, /* Segment ID */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 2, 6, 68, 5, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0,
+};
+
+static uint8_t reportdata_80_80_gen3[] = {
+ /* Segment 1 */
+#ifdef BIG_ENDIAN_HOST
+ 0x12, 0x34, 0x56, 0x78, /* fft_timestamp */
+ 0xfa, /* fft_hdr_sig */
+ 0x03, /* fft_hdr_tag */
+ 0x00, /* fft_hdr_length */
+ 0x44,
+ 0x0f, 0xf6, 0x00, 0xe0,
+ 0x00, 0x00, 0x2f, 0xba,
+ 0x20, 0xb4, 0x2c, 0x01,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#else
+ 0x78, 0x56, 0x34, 0x12, /* fft_timestamp */
+ 0x44, /* fft_hdr_length */
+ 0x00,
+ 0x03, /* fft_hdr_tag */
+ 0xfa, /* fft_hdr_sig */
+ 0xe0, 0x00, 0xf6, 0x0f,
+ 0xba, 0x2f, 0x00, 0x00,
+ 0x01, 0x2c, 0xb4, 0x20,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 2, 6, 68, 5, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+
+ /* Segment 2 */
+#ifdef BIG_ENDIAN_HOST
+ 0x12, 0x34, 0x56, 0x78, /* fft_timestamp */
+ 0xfa, /* fft_hdr_sig */
+ 0x03, /* fft_hdr_tag */
+ 0x00, /* fft_hdr_length */
+ 0x44,
+ 0x0f, 0xf6, 0x00, 0xe1,
+ 0x00, 0x00, 0x2f, 0xba,
+ 0x20, 0xb4, 0x2c, 0x01,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#else
+ 0x78, 0x56, 0x34, 0x12, /* fft_timestamp */
+ 0x44, /* fft_hdr_length */
+ 0x00,
+ 0x03, /* fft_hdr_tag */
+ 0xfa, /* fft_hdr_sig */
+ 0xe1, 0x00, 0xf6, 0x0f,
+ 0xba, 0x2f, 0x00, 0x00,
+ 0x01, 0x2c, 0xb4, 0x20,
+ 0x00, 0x00, 0x00, 0x00, /* reserved */
+#endif /* BIG_ENDIAN_HOST */
+ /* FFT Data */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
+ 1, 1, 2, 6, 68, 5, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static struct target_if_spectral_rfqual_info rfqual_info_80_80 = {
+ .rssi_comb = 1,
+
+ .pc_rssi_info[0].rssi_pri20 = 1,
+ .pc_rssi_info[0].rssi_sec20 = 17,
+ .pc_rssi_info[0].rssi_sec40 = 40,
+ .pc_rssi_info[0].rssi_sec80 = 128,
+
+ .pc_rssi_info[1].rssi_pri20 = 128,
+ .pc_rssi_info[1].rssi_sec20 = 128,
+ .pc_rssi_info[1].rssi_sec40 = 128,
+ .pc_rssi_info[1].rssi_sec80 = 128,
+
+ .pc_rssi_info[2].rssi_pri20 = 128,
+ .pc_rssi_info[2].rssi_sec20 = 128,
+ .pc_rssi_info[2].rssi_sec40 = 128,
+ .pc_rssi_info[2].rssi_sec80 = 128,
+
+ .pc_rssi_info[3].rssi_pri20 = 128,
+ .pc_rssi_info[3].rssi_sec20 = 128,
+ .pc_rssi_info[3].rssi_sec40 = 128,
+ .pc_rssi_info[3].rssi_sec80 = 128,
+
+ .noise_floor[0] = -90,
+ .noise_floor[1] = -90,
+ .noise_floor[2] = -90,
+ .noise_floor[3] = -90,
+ };
+
+static struct target_if_spectral_chan_info chan_info_80_80 = {
+ .center_freq1 = 5210,
+ .center_freq2 = 5530,
+ .chan_width = 160,
+ };
+
+static struct spectral_config config_80_80_1 = {
+ .ss_fft_period = 1,
+ .ss_period = 35,
+ .ss_count = 0,
+ .ss_short_report = 1,
+ .radar_bin_thresh_sel = 0,
+ .ss_spectral_pri = 1,
+ .ss_fft_size = 9,
+ .ss_gc_ena = 1,
+ .ss_restart_ena = 0,
+ .ss_noise_floor_ref = 65440,
+ .ss_init_delay = 80,
+ .ss_nb_tone_thr = 12,
+ .ss_str_bin_thr = 8,
+ .ss_wb_rpt_mode = 0,
+ .ss_rssi_rpt_mode = 0,
+ .ss_rssi_thr = 240,
+ .ss_pwr_format = 0,
+ .ss_rpt_mode = 2,
+ .ss_bin_scale = 1,
+ .ss_dBm_adj = 1,
+ .ss_chn_mask = 1,
+ .ss_nf_cal[0] = 0,
+ .ss_nf_cal[1] = 0,
+ .ss_nf_cal[2] = 0,
+ .ss_nf_cal[3] = 0,
+ .ss_nf_cal[4] = 0,
+ .ss_nf_cal[5] = 0,
+ .ss_nf_pwr[0] = 0,
+ .ss_nf_pwr[1] = 0,
+ .ss_nf_pwr[2] = 0,
+ .ss_nf_pwr[3] = 0,
+ .ss_nf_pwr[4] = 0,
+ .ss_nf_pwr[5] = 0,
+ .ss_nf_temp_data = 0,
+ };
+
+#endif /* QCA_SUPPORT_SPECTRAL_SIMULATION */
+#endif /* _SPECTRAL_SIM_INTERNAL_H_ */