From de0cb20d071d9f97c80f8f49c790664f6f0dd589 Mon Sep 17 00:00:00 2001 From: Shiva Krishna Pittala Date: Tue, 7 Nov 2017 11:56:58 +0530 Subject: [PATCH] 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 --- spectral/Kbuild | 205 ++ spectral/core/spectral_cmn_api_i.h | 135 + spectral/core/spectral_common.c | 562 ++++ spectral/core/spectral_da_api_i.h | 34 + spectral/core/spectral_defs_i.h | 113 + spectral/core/spectral_direct_attach.c | 209 ++ spectral/core/spectral_module.c | 55 + spectral/core/spectral_offload.c | 177 ++ spectral/core/spectral_ol_api_i.h | 34 + .../inc/wlan_spectral_public_structs.h | 477 ++++ .../dispatcher/inc/wlan_spectral_tgt_api.h | 46 + .../dispatcher/inc/wlan_spectral_ucfg_api.h | 46 + .../dispatcher/inc/wlan_spectral_utils_api.h | 58 + .../dispatcher/src/wlan_spectral_tgt_api.c | 45 + .../dispatcher/src/wlan_spectral_ucfg_api.c | 50 + .../dispatcher/src/wlan_spectral_utils_api.c | 91 + target_if/spectral/target_if_spectral.c | 2509 +++++++++++++++++ target_if/spectral/target_if_spectral.h | 982 +++++++ .../spectral/target_if_spectral_netlink.c | 590 ++++ .../spectral/target_if_spectral_phyerr.c | 1653 +++++++++++ target_if/spectral/target_if_spectral_sim.c | 958 +++++++ target_if/spectral/target_if_spectral_sim.h | 108 + .../spectral/target_if_spectral_sim_int.h | 961 +++++++ 23 files changed, 10098 insertions(+) create mode 100644 spectral/Kbuild create mode 100644 spectral/core/spectral_cmn_api_i.h create mode 100644 spectral/core/spectral_common.c create mode 100644 spectral/core/spectral_da_api_i.h create mode 100644 spectral/core/spectral_defs_i.h create mode 100644 spectral/core/spectral_direct_attach.c create mode 100644 spectral/core/spectral_module.c create mode 100644 spectral/core/spectral_offload.c create mode 100644 spectral/core/spectral_ol_api_i.h create mode 100644 spectral/dispatcher/inc/wlan_spectral_public_structs.h create mode 100644 spectral/dispatcher/inc/wlan_spectral_tgt_api.h create mode 100644 spectral/dispatcher/inc/wlan_spectral_ucfg_api.h create mode 100644 spectral/dispatcher/inc/wlan_spectral_utils_api.h create mode 100644 spectral/dispatcher/src/wlan_spectral_tgt_api.c create mode 100644 spectral/dispatcher/src/wlan_spectral_ucfg_api.c create mode 100644 spectral/dispatcher/src/wlan_spectral_utils_api.c create mode 100644 target_if/spectral/target_if_spectral.c create mode 100644 target_if/spectral/target_if_spectral.h create mode 100644 target_if/spectral/target_if_spectral_netlink.c create mode 100644 target_if/spectral/target_if_spectral_phyerr.c create mode 100644 target_if/spectral/target_if_spectral_sim.c create mode 100644 target_if/spectral/target_if_spectral_sim.h create mode 100644 target_if/spectral/target_if_spectral_sim_int.h diff --git a/spectral/Kbuild b/spectral/Kbuild new file mode 100644 index 000000000000..eac23f465c39 --- /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 000000000000..4436c0de66c9 --- /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 000000000000..c3e2303aab5f --- /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 +#include +#include +#include +#include + +/** + * 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 000000000000..c0dca87dbd75 --- /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 000000000000..6c6bd7bf9011 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 000000000000..58ab4d72928e --- /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 000000000000..ce42e639b880 --- /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 +#include +#include +#include + +/** + * 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 000000000000..b4a352ac56c4 --- /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 000000000000..654165498822 --- /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 000000000000..c6fe1d82a605 --- /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 +#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 000000000000..86f2972c56f6 --- /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 +#include + +/** + * 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 000000000000..040049418081 --- /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 +#include + +/* 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 000000000000..26825fa69779 --- /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 +#include + +/** + * 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 000000000000..a3fa5bc90c26 --- /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 +#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 000000000000..b063f9d52629 --- /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 +#include "../../core/spectral_cmn_api_i.h" +#include + +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 000000000000..d65a9cd22aa7 --- /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 +#include +#include "../../core/spectral_cmn_api_i.h" +#include + +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 000000000000..5c02c50f8149 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @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 000000000000..d916e90e2842 --- /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 +#include +#include +#include +#include +#include + +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 000000000000..458e2ce316b9 --- /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 +#include +#include +#include +#include +#include +#include +#include + +#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 000000000000..6f534b7a0ff1 --- /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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +/* 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 000000000000..e71e3b1f34a1 --- /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 + +/* 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 000000000000..d0e94111b344 --- /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 000000000000..c0b53327a4e7 --- /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_ */